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