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