• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "surface_draw.h"
17 #include <algorithm>
18 #include <surface.h>
19 #include <transaction/rs_interfaces.h>
20 #include <ui/rs_surface_extractor.h>
21 
22 #include "image/bitmap.h"
23 #include "image_source.h"
24 #include "image_type.h"
25 #include "image_utils.h"
26 #include "pixel_map.h"
27 #include "surface_capture_future.h"
28 #include "window_manager_hilog.h"
29 
30 namespace OHOS {
31 namespace Rosen {
32 namespace {
33     constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "SurfaceDraw"};
34     constexpr uint32_t IMAGE_BYTES_STRIDE = 4;
35 } // namespace
36 
DrawImage(std::shared_ptr<RSSurfaceNode> surfaceNode,int32_t bufferWidth,int32_t bufferHeight,const std::string & imagePath)37 bool SurfaceDraw::DrawImage(std::shared_ptr<RSSurfaceNode> surfaceNode, int32_t bufferWidth,
38     int32_t bufferHeight, const std::string& imagePath)
39 {
40     sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
41     if (layer == nullptr) {
42         WLOGFE("layer is nullptr");
43         return false;
44     }
45     sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight);
46     if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
47         return false;
48     }
49     auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
50     if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), imagePath)) {
51         WLOGE("draw window pixel failed");
52         return false;
53     }
54     OHOS::BufferFlushConfig flushConfig = {
55         .damage = {
56             .w = buffer->GetWidth(),
57             .h = buffer->GetHeight(),
58         },
59     };
60     OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig);
61     if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
62         WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str());
63         return false;
64     }
65     return true;
66 }
67 
DrawImage(std::shared_ptr<RSSurfaceNode> surfaceNode,int32_t bufferWidth,int32_t bufferHeight,std::shared_ptr<Media::PixelMap> pixelMap)68 bool SurfaceDraw::DrawImage(std::shared_ptr<RSSurfaceNode> surfaceNode, int32_t bufferWidth,
69     int32_t bufferHeight, std::shared_ptr<Media::PixelMap> pixelMap)
70 {
71     sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
72     if (layer == nullptr) {
73         WLOGFE("layer is nullptr");
74         return false;
75     }
76     sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight);
77     if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
78         return false;
79     }
80     auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
81     if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), pixelMap)) {
82         WLOGE("draw window pixel failed");
83         return false;
84     }
85     OHOS::BufferFlushConfig flushConfig = {
86         .damage = {
87             .w = buffer->GetWidth(),
88             .h = buffer->GetHeight(),
89         },
90     };
91     OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig);
92     if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
93         WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str());
94         return false;
95     }
96     return true;
97 }
98 
DrawColor(std::shared_ptr<RSSurfaceNode> surfaceNode,int32_t bufferWidth,int32_t bufferHeight,uint32_t color)99 bool SurfaceDraw::DrawColor(std::shared_ptr<RSSurfaceNode> surfaceNode, int32_t bufferWidth,
100     int32_t bufferHeight, uint32_t color)
101 {
102     sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
103     if (layer == nullptr) {
104         WLOGFE("layer is nullptr");
105         return false;
106     }
107     sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight);
108     if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
109         return false;
110     }
111     auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
112     if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), color)) {
113         WLOGE("draw window color failed");
114         return false;
115     }
116     OHOS::BufferFlushConfig flushConfig = {
117         .damage = {
118             .w = buffer->GetWidth(),
119             .h = buffer->GetHeight(),
120         },
121     };
122     OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig);
123     if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) {
124         WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str());
125         return false;
126     }
127     return true;
128 }
129 
GetLayer(std::shared_ptr<RSSurfaceNode> surfaceNode)130 sptr<OHOS::Surface> SurfaceDraw::GetLayer(std::shared_ptr<RSSurfaceNode> surfaceNode)
131 {
132     if (surfaceNode == nullptr) {
133         return nullptr;
134     }
135     return surfaceNode->GetSurface();
136 }
137 
GetSurfaceBuffer(sptr<OHOS::Surface> layer,int32_t bufferWidth,int32_t bufferHeight)138 sptr<OHOS::SurfaceBuffer> SurfaceDraw::GetSurfaceBuffer(sptr<OHOS::Surface> layer,
139     int32_t bufferWidth, int32_t bufferHeight)
140 {
141     sptr<OHOS::SurfaceBuffer> buffer;
142     int32_t releaseFence = 0;
143     OHOS::BufferRequestConfig config = {
144         .width = bufferWidth,
145         .height = bufferHeight,
146         .strideAlignment = 0x8,
147         .format = PIXEL_FMT_RGBA_8888,
148         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
149     };
150 
151     OHOS::SurfaceError ret = layer->RequestBuffer(buffer, releaseFence, config);
152     if (ret != OHOS::SURFACE_ERROR_OK) {
153         WLOGFE("request buffer ret:%{public}s", SurfaceErrorStr(ret).c_str());
154         return nullptr;
155     }
156     return buffer;
157 }
158 
DecodeImageToPixelMap(const std::string & imagePath)159 std::unique_ptr<OHOS::Media::PixelMap> SurfaceDraw::DecodeImageToPixelMap(const std::string &imagePath)
160 {
161     OHOS::Media::SourceOptions opts;
162     opts.formatHint = "image/png";
163     uint32_t ret = 0;
164     auto imageSource = OHOS::Media::ImageSource::CreateImageSource(imagePath, opts, ret);
165     if (imageSource == nullptr) {
166         WLOGFE("invalid image path.");
167         return nullptr;
168     }
169     std::set<std::string> formats;
170     ret = imageSource->GetSupportedFormats(formats);
171     WLOGFD("get supported format ret:%{public}u", ret);
172 
173     OHOS::Media::DecodeOptions decodeOpts;
174     std::unique_ptr<OHOS::Media::PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, ret);
175     if (pixelMap == nullptr) {
176         WLOGFE("pixelMap is nullptr");
177     }
178     return pixelMap;
179 }
180 
DrawPixelmap(Drawing::Canvas & canvas,const std::string & imagePath)181 void SurfaceDraw::DrawPixelmap(Drawing::Canvas &canvas, const std::string& imagePath)
182 {
183     std::unique_ptr<OHOS::Media::PixelMap> pixelmap = DecodeImageToPixelMap(imagePath);
184     if (pixelmap == nullptr) {
185         WLOGFE("drawing pixel map is nullptr");
186         return;
187     }
188     Drawing::Pen pen;
189     pen.SetAntiAlias(true);
190     pen.SetColor(Drawing::Color::COLOR_BLUE);
191     Drawing::scalar penWidth = 1;
192     pen.SetWidth(penWidth);
193     canvas.AttachPen(pen);
194     canvas.DrawBitmap(*pixelmap, 0, 0);
195 }
196 
DoDraw(uint8_t * addr,uint32_t width,uint32_t height,const std::string & imagePath)197 bool SurfaceDraw::DoDraw(uint8_t *addr, uint32_t width, uint32_t height, const std::string& imagePath)
198 {
199     Drawing::Bitmap bitmap;
200     Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888,
201         Drawing::AlphaType::ALPHATYPE_OPAQUE };
202     bitmap.Build(width, height, format);
203     Drawing::Canvas canvas;
204     canvas.Bind(bitmap);
205     canvas.Clear(Drawing::Color::COLOR_TRANSPARENT);
206     DrawPixelmap(canvas, imagePath);
207     uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE;
208     errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize);
209     if (ret != EOK) {
210         WLOGFE("draw failed");
211         return false;
212     }
213     return true;
214 }
215 
DoDraw(uint8_t * addr,uint32_t width,uint32_t height,std::shared_ptr<Media::PixelMap> pixelMap)216 bool SurfaceDraw::DoDraw(uint8_t *addr, uint32_t width, uint32_t height, std::shared_ptr<Media::PixelMap> pixelMap)
217 {
218     Drawing::Bitmap bitmap;
219     Drawing::Canvas canvas;
220     Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE };
221     bitmap.Build(width, height, format);
222     canvas.Bind(bitmap);
223     canvas.Clear(Drawing::Color::COLOR_TRANSPARENT);
224 
225     Drawing::Image image;
226     Drawing::Bitmap imageBitmap;
227     Drawing::SamplingOptions sampling = Drawing::SamplingOptions(Drawing::FilterMode::NEAREST,
228         Drawing::MipmapMode::NEAREST);
229     imageBitmap.Build(pixelMap->GetWidth(), pixelMap->GetHeight(), format);
230     imageBitmap.SetPixels(const_cast<uint8_t*>(pixelMap->GetPixels()));
231     image.BuildFromBitmap(imageBitmap);
232 
233     Drawing::Rect dst(0, 0, width, height);
234     Drawing::Rect src(0, 0, pixelMap->GetWidth(), pixelMap->GetHeight());
235     canvas.DrawImageRect(image, src, dst, sampling);
236 
237     uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE;
238     errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize);
239     if (ret != EOK) {
240         WLOGFE("draw failed");
241         return false;
242     }
243     return true;
244 }
245 
DoDraw(uint8_t * addr,uint32_t width,uint32_t height,uint32_t color)246 bool SurfaceDraw::DoDraw(uint8_t *addr, uint32_t width, uint32_t height, uint32_t color)
247 {
248     Drawing::Bitmap bitmap;
249     Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888,
250         Drawing::AlphaType::ALPHATYPE_OPAQUE };
251     bitmap.Build(width, height, format);
252     Drawing::Canvas canvas;
253     canvas.Bind(bitmap);
254     canvas.Clear(color);
255 
256     uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE;
257     errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize);
258     if (ret != EOK) {
259         WLOGFE("draw failed");
260         return false;
261     }
262     return true;
263 }
264 
DrawImageRect(std::shared_ptr<RSSurfaceNode> surfaceNode,Rect rect,std::shared_ptr<Media::PixelMap> pixelMap,uint32_t color,bool fillWindow)265 bool SurfaceDraw::DrawImageRect(std::shared_ptr<RSSurfaceNode> surfaceNode, Rect rect,
266     std::shared_ptr<Media::PixelMap> pixelMap, uint32_t color, bool fillWindow)
267 {
268     int32_t winHeight = static_cast<int32_t>(rect.height_);
269     int32_t winWidth = static_cast<int32_t>(rect.width_);
270     sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
271     if (layer == nullptr) {
272         WLOGFE("layer is nullptr");
273         return false;
274     }
275     sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, winWidth, winHeight);
276     if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
277         return false;
278     }
279     if (!DoDrawImageRect(buffer, rect, pixelMap, color, fillWindow)) {
280         WLOGE("draw image rect failed.");
281         return false;
282     }
283     OHOS::BufferFlushConfig flushConfig = {
284         .damage = {
285             .w = buffer->GetWidth(),
286             .h = buffer->GetHeight(),
287         },
288     };
289     OHOS::SurfaceError surfaceRet = layer->FlushBuffer(buffer, -1, flushConfig);
290     if (surfaceRet != OHOS::SurfaceError::SURFACE_ERROR_OK) {
291         WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(surfaceRet).c_str());
292         return false;
293     }
294     return true;
295 }
296 
DoDrawImageRect(sptr<OHOS::SurfaceBuffer> buffer,const Rect & rect,std::shared_ptr<Media::PixelMap> pixelMap,uint32_t color,bool fillWindow)297 bool SurfaceDraw::DoDrawImageRect(sptr<OHOS::SurfaceBuffer> buffer, const Rect& rect,
298     std::shared_ptr<Media::PixelMap> pixelMap, uint32_t color, bool fillWindow)
299 {
300     int32_t winWidth = static_cast<int32_t>(rect.width_);
301     int32_t winHeight = static_cast<int32_t>(rect.height_);
302     // actual width of the surface buffer after alignment
303     auto bufferStride = buffer->GetStride();
304     int32_t alignWidth = bufferStride / static_cast<int32_t>(IMAGE_BYTES_STRIDE);
305     WLOGFD("drawing image rect win width: %{public}d win height: %{public}d align width:%{public}d.",
306         winWidth, winHeight, alignWidth);
307     if (pixelMap == nullptr) {
308         WLOGFE("drawing pixel map failed, because pixel map is nullptr.");
309         return false;
310     }
311     if (pixelMap->GetHeight() <= 0 || pixelMap->GetWidth() <= 0 || winWidth <= 0 || winHeight <= 0) {
312         WLOGFE("drawing pixel map failed, because width or height is invalid.");
313         return false;
314     }
315     float xAxis = static_cast<float>(winWidth) / pixelMap->GetWidth();
316     float yAxis = static_cast<float>(winHeight) / pixelMap->GetHeight();
317     float axis = std::min(xAxis, yAxis);
318     if (axis < 1.0) {
319         // scale when the size of the pixel map is larger than the window
320         // use axis to scale equally
321         pixelMap->scale(axis, axis);
322     } else if (fillWindow) {
323         // scale snapshot to whole window
324         pixelMap->scale(xAxis, yAxis);
325     }
326     int left = (winWidth - pixelMap->GetWidth()) / 2; // 2 is the left and right boundaries of the window
327     int top = (winHeight - pixelMap->GetHeight()) / 2; // 2 is the top and bottom boundaries of the window
328     WLOGFD("pixelMap width: %{public}d win height: %{public}d left:%{public}d top:%{public}d.",
329         pixelMap->GetWidth(), pixelMap->GetHeight(), left, top);
330     Drawing::Bitmap bitmap;
331     Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888,
332         Drawing::AlphaType::ALPHATYPE_OPAQUE };
333     bitmap.Build(alignWidth, winHeight, format);
334     Drawing::Canvas canvas;
335     canvas.Bind(bitmap);
336     canvas.Clear(color);
337     canvas.DrawBitmap(*pixelMap, left, top);
338     // bufferSize is actual size of the surface buffer after alignment
339     int32_t bufferSize = bufferStride * winHeight;
340     uint8_t* bitmapAddr = static_cast<uint8_t*>(bitmap.GetPixels());
341     auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
342     errno_t ret = memcpy_s(addr, bufferSize, bitmapAddr, bufferSize);
343     if (ret != EOK) {
344         WLOGFE("draw image rect failed, because copy bitmap to buffer failed.");
345         return false;
346     }
347     return true;
348 }
349 
GetSurfaceSnapshot(const std::shared_ptr<RSSurfaceNode> surfaceNode,std::shared_ptr<Media::PixelMap> & pixelMap,int32_t timeoutMs,float scaleW,float scaleH)350 bool SurfaceDraw::GetSurfaceSnapshot(const std::shared_ptr<RSSurfaceNode> surfaceNode,
351     std::shared_ptr<Media::PixelMap>&pixelMap, int32_t timeoutMs, float scaleW, float scaleH)
352 {
353     if (surfaceNode == nullptr) {
354         WLOGFE("surfaceNode is null");
355         return false;
356     }
357     std::shared_ptr<SurfaceCaptureFuture> callback = std::make_shared<SurfaceCaptureFuture>();
358     if (RSInterfaces::GetInstance().TakeSurfaceCapture(surfaceNode, callback, scaleW, scaleH)) {
359         pixelMap = callback->GetResult(timeoutMs); // get pixelmap time out ms
360     }
361     if (pixelMap == nullptr) {
362         WLOGE("get surface snapshot timeout.");
363         return false;
364     }
365     return true;
366 }
367 
DrawMasking(std::shared_ptr<RSSurfaceNode> surfaceNode,Rect screenRect,Rect transparentRect)368 bool SurfaceDraw::DrawMasking(std::shared_ptr<RSSurfaceNode> surfaceNode, Rect screenRect,
369     Rect transparentRect)
370 {
371     int32_t screenHeight = static_cast<int32_t>(screenRect.height_);
372     int32_t screenWidth = static_cast<int32_t>(screenRect.width_);
373     int32_t transparentHeight = static_cast<int32_t>(transparentRect.height_);
374     int32_t transparentWidth = static_cast<int32_t>(transparentRect.width_);
375     sptr<OHOS::Surface> layer = GetLayer(surfaceNode);
376     if (layer == nullptr) {
377         WLOGFE("layer is nullptr");
378         return false;
379     }
380     sptr<OHOS::SurfaceBuffer> buffer = GetSurfaceBuffer(layer, screenWidth, screenHeight);
381     if (buffer == nullptr || buffer->GetVirAddr() == nullptr) {
382         return false;
383     }
384     auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
385     Drawing::Bitmap fullbitmap;
386     Drawing::BitmapFormat fullBitmapFormat { Drawing::ColorType::COLORTYPE_RGBA_8888,
387         Drawing::AlphaType::ALPHATYPE_OPAQUE };
388     fullbitmap.Build(screenWidth, screenHeight, fullBitmapFormat);
389     Drawing::Canvas canvas;
390     canvas.Bind(fullbitmap);
391     canvas.Clear(0xFF000000);
392     Drawing::Bitmap transBitmap;
393     Drawing::BitmapFormat transBitmapFormat { Drawing::ColorType::COLORTYPE_RGBA_8888,
394         Drawing::AlphaType::ALPHATYPE_OPAQUE };
395     transBitmap.Build(transparentWidth, transparentHeight, transBitmapFormat);
396     transBitmap.ClearWithColor(0);
397     canvas.DrawBitmap(transBitmap, static_cast<Drawing::scalar>(transparentRect.posX_),
398         static_cast<Drawing::scalar>(transparentRect.posY_));
399 
400     uint32_t addrSize = static_cast<uint32_t>(screenWidth * screenHeight * IMAGE_BYTES_STRIDE);
401     errno_t ret = memcpy_s(addr, addrSize, fullbitmap.GetPixels(), addrSize);
402     if (ret != EOK) {
403         WLOGFE("draw failed");
404         return false;
405     }
406     OHOS::BufferFlushConfig flushConfig = {
407         .damage = {
408             .w = buffer->GetWidth(),
409             .h = buffer->GetHeight(),
410         },
411     };
412     OHOS::SurfaceError surfaceRet = layer->FlushBuffer(buffer, -1, flushConfig);
413     if (surfaceRet != OHOS::SurfaceError::SURFACE_ERROR_OK) {
414         WLOGFE("draw masking FlushBuffer ret:%{public}s", SurfaceErrorStr(surfaceRet).c_str());
415         return false;
416     }
417     return true;
418 }
419 } // Rosen
420 } // OHOS