/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "surface_draw.h" #include #include #include #include #include #include "image/bitmap.h" #include "image_source.h" #include "image_type.h" #include "image_utils.h" #include "render/rs_pixel_map_util.h" #include "surface_capture_future.h" #include "window_manager_hilog.h" namespace OHOS { namespace Rosen { namespace { constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "SurfaceDraw"}; constexpr uint32_t IMAGE_BYTES_STRIDE = 4; } // namespace bool SurfaceDraw::DrawImage(std::shared_ptr surfaceNode, int32_t bufferWidth, int32_t bufferHeight, const std::string& imagePath) { sptr layer = GetLayer(surfaceNode); if (layer == nullptr) { WLOGFE("layer is nullptr"); return false; } sptr buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight); if (buffer == nullptr || buffer->GetVirAddr() == nullptr) { return false; } auto addr = static_cast(buffer->GetVirAddr()); if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), imagePath)) { WLOGE("draw window pixel failed"); return false; } OHOS::BufferFlushConfig flushConfig = { .damage = { .w = buffer->GetWidth(), .h = buffer->GetHeight(), }, }; OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig); if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) { WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str()); return false; } return true; } bool SurfaceDraw::DrawImage(std::shared_ptr surfaceNode, int32_t bufferWidth, int32_t bufferHeight, std::shared_ptr pixelMap) { sptr layer = GetLayer(surfaceNode); if (layer == nullptr) { WLOGFE("layer is nullptr"); return false; } sptr buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight); if (buffer == nullptr || buffer->GetVirAddr() == nullptr) { return false; } auto addr = static_cast(buffer->GetVirAddr()); if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), pixelMap)) { WLOGE("draw window pixel failed"); return false; } OHOS::BufferFlushConfig flushConfig = { .damage = { .w = buffer->GetWidth(), .h = buffer->GetHeight(), }, }; OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig); if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) { WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str()); return false; } return true; } bool SurfaceDraw::DrawColor(std::shared_ptr surfaceNode, int32_t bufferWidth, int32_t bufferHeight, uint32_t color) { sptr layer = GetLayer(surfaceNode); if (layer == nullptr) { WLOGFE("layer is nullptr"); return false; } sptr buffer = GetSurfaceBuffer(layer, bufferWidth, bufferHeight); if (buffer == nullptr || buffer->GetVirAddr() == nullptr) { return false; } auto addr = static_cast(buffer->GetVirAddr()); if (!DoDraw(addr, buffer->GetWidth(), buffer->GetHeight(), color)) { WLOGE("draw window color failed"); return false; } OHOS::BufferFlushConfig flushConfig = { .damage = { .w = buffer->GetWidth(), .h = buffer->GetHeight(), }, }; OHOS::SurfaceError ret = layer->FlushBuffer(buffer, -1, flushConfig); if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) { WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(ret).c_str()); return false; } return true; } sptr SurfaceDraw::GetLayer(std::shared_ptr surfaceNode) { if (surfaceNode == nullptr) { return nullptr; } return surfaceNode->GetSurface(); } sptr SurfaceDraw::GetSurfaceBuffer(sptr layer, int32_t bufferWidth, int32_t bufferHeight) { sptr buffer; int32_t releaseFence = 0; OHOS::BufferRequestConfig config = { .width = bufferWidth, .height = bufferHeight, .strideAlignment = 0x8, .format = GRAPHIC_PIXEL_FMT_RGBA_8888, .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA, }; OHOS::SurfaceError ret = layer->RequestBuffer(buffer, releaseFence, config); if (ret != OHOS::SURFACE_ERROR_OK) { WLOGFE("request buffer ret:%{public}s", SurfaceErrorStr(ret).c_str()); return nullptr; } return buffer; } std::unique_ptr SurfaceDraw::DecodeImageToPixelMap(const std::string& imagePath) { OHOS::Media::SourceOptions opts; opts.formatHint = "image/png"; uint32_t ret = 0; auto imageSource = OHOS::Media::ImageSource::CreateImageSource(imagePath, opts, ret); if (imageSource == nullptr) { WLOGFE("invalid image path."); return nullptr; } std::set formats; ret = imageSource->GetSupportedFormats(formats); WLOGFD("get supported format ret:%{public}u", ret); OHOS::Media::DecodeOptions decodeOpts; std::unique_ptr pixelMap = imageSource->CreatePixelMap(decodeOpts, ret); if (pixelMap == nullptr) { WLOGFE("pixelMap is nullptr"); } return pixelMap; } void SurfaceDraw::DrawPixelmap(Drawing::Canvas& canvas, const std::string& imagePath) { std::unique_ptr pixelmap = DecodeImageToPixelMap(imagePath); if (pixelmap == nullptr) { WLOGFE("drawing pixel map is nullptr"); return; } Drawing::Pen pen; pen.SetAntiAlias(true); pen.SetColor(Drawing::Color::COLOR_BLUE); Drawing::scalar penWidth = 1; pen.SetWidth(penWidth); canvas.AttachPen(pen); RSPixelMapUtil::DrawPixelMap(canvas, *pixelmap, 0, 0); } bool SurfaceDraw::DoDraw(uint8_t* addr, uint32_t width, uint32_t height, const std::string& imagePath) { Drawing::Bitmap bitmap; Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE }; bitmap.Build(width, height, format); Drawing::Canvas canvas; canvas.Bind(bitmap); canvas.Clear(Drawing::Color::COLOR_TRANSPARENT); DrawPixelmap(canvas, imagePath); uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE; errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize); if (ret != EOK) { WLOGFE("draw failed"); return false; } return true; } bool SurfaceDraw::DoDraw(uint8_t* addr, uint32_t width, uint32_t height, std::shared_ptr pixelMap) { Drawing::Bitmap bitmap; Drawing::Canvas canvas; Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE }; bitmap.Build(width, height, format); canvas.Bind(bitmap); canvas.Clear(Drawing::Color::COLOR_TRANSPARENT); Drawing::Image image; Drawing::Bitmap imageBitmap; Drawing::SamplingOptions sampling = Drawing::SamplingOptions(Drawing::FilterMode::NEAREST, Drawing::MipmapMode::NEAREST); imageBitmap.Build(pixelMap->GetWidth(), pixelMap->GetHeight(), format); imageBitmap.SetPixels(const_cast(pixelMap->GetPixels())); image.BuildFromBitmap(imageBitmap); Drawing::Rect dst(0, 0, width, height); Drawing::Rect src(0, 0, pixelMap->GetWidth(), pixelMap->GetHeight()); canvas.DrawImageRect(image, src, dst, sampling); uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE; errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize); if (ret != EOK) { WLOGFE("draw failed"); return false; } return true; } bool SurfaceDraw::DoDraw(uint8_t* addr, uint32_t width, uint32_t height, uint32_t color) { Drawing::Bitmap bitmap; Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE }; bitmap.Build(width, height, format); Drawing::Canvas canvas; canvas.Bind(bitmap); canvas.Clear(color); uint32_t addrSize = width * height * IMAGE_BYTES_STRIDE; errno_t ret = memcpy_s(addr, addrSize, bitmap.GetPixels(), addrSize); if (ret != EOK) { WLOGFE("draw failed"); return false; } return true; } bool SurfaceDraw::DrawImageRect(std::shared_ptr surfaceNode, Rect rect, std::shared_ptr pixelMap, uint32_t color, bool fillWindow) { int32_t winHeight = static_cast(rect.height_); int32_t winWidth = static_cast(rect.width_); sptr layer = GetLayer(surfaceNode); if (layer == nullptr) { WLOGFE("layer is nullptr"); return false; } sptr buffer = GetSurfaceBuffer(layer, winWidth, winHeight); if (buffer == nullptr || buffer->GetVirAddr() == nullptr) { return false; } if (!DoDrawImageRect(buffer, rect, pixelMap, color, fillWindow)) { WLOGE("draw image rect failed."); return false; } OHOS::BufferFlushConfig flushConfig = { .damage = { .w = buffer->GetWidth(), .h = buffer->GetHeight(), }, }; OHOS::SurfaceError surfaceRet = layer->FlushBuffer(buffer, -1, flushConfig); if (surfaceRet != OHOS::SurfaceError::SURFACE_ERROR_OK) { WLOGFE("draw pointer FlushBuffer ret:%{public}s", SurfaceErrorStr(surfaceRet).c_str()); return false; } return true; } bool SurfaceDraw::DoDrawImageRect(sptr buffer, const Rect& rect, std::shared_ptr pixelMap, uint32_t color, bool fillWindow) { int32_t winWidth = static_cast(rect.width_); int32_t winHeight = static_cast(rect.height_); // actual width of the surface buffer after alignment auto bufferStride = buffer->GetStride(); int32_t alignWidth = bufferStride / static_cast(IMAGE_BYTES_STRIDE); if (pixelMap == nullptr) { WLOGFE("drawing pixel map failed, because pixel map is nullptr."); return false; } if (pixelMap->GetHeight() <= 0 || pixelMap->GetWidth() <= 0 || winWidth <= 0 || winHeight <= 0) { WLOGFE("drawing pixel map failed, because width or height is invalid."); return false; } Drawing::Bitmap bitmap; Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE }; bitmap.Build(alignWidth, winHeight, format); Drawing::Canvas canvas; canvas.Bind(bitmap); canvas.Clear(color); float xAxis = static_cast(winWidth) / pixelMap->GetWidth(); float yAxis = static_cast(winHeight) / pixelMap->GetHeight(); float axis = std::min(xAxis, yAxis); int scaledPixelMapW = pixelMap->GetWidth(); int scaledPixelMapH = pixelMap->GetHeight(); if (axis < 1.0) { canvas.Scale(axis, axis); scaledPixelMapW = scaledPixelMapW * axis; scaledPixelMapH = scaledPixelMapH * axis; } else if (fillWindow) { // scale snapshot to whole window canvas.Scale(xAxis, yAxis); scaledPixelMapW = winWidth; scaledPixelMapH = winHeight; } int left = (winWidth - scaledPixelMapW) / 2; // 2 is the left and right boundaries of the win int top = (winHeight - scaledPixelMapH) / 2; // 2 is the top and bottom boundaries of the win WLOGFD("pixelMap width: %{public}d win height: %{public}d left:%{public}d top:%{public}d.", pixelMap->GetWidth(), pixelMap->GetHeight(), left, top); RSPixelMapUtil::DrawPixelMap(canvas, *pixelMap, left, top); // bufferSize is actual size of the surface buffer after alignment int32_t bufferSize = bufferStride * winHeight; uint8_t* bitmapAddr = static_cast(bitmap.GetPixels()); auto addr = static_cast(buffer->GetVirAddr()); errno_t ret = memcpy_s(addr, bufferSize, bitmapAddr, bufferSize); if (ret != EOK) { WLOGFE("draw image rect failed, because copy bitmap to buffer failed."); return false; } return true; } bool SurfaceDraw::GetSurfaceSnapshot(const std::shared_ptr surfaceNode, std::shared_ptr&pixelMap, int32_t timeoutMs, float scaleW, float scaleH) { if (surfaceNode == nullptr) { WLOGFE("surfaceNode is null"); return false; } HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "SurfaceDraw:GetSurfaceSnapshot(%llu)", surfaceNode->GetId()); std::shared_ptr callback = std::make_shared(); RSSurfaceCaptureConfig config = { .scaleX = scaleW, .scaleY = scaleH, }; if (RSInterfaces::GetInstance().TakeSurfaceCapture(surfaceNode, callback, config)) { pixelMap = callback->GetResult(timeoutMs); // get pixelmap time out ms } if (pixelMap == nullptr) { WLOGE("get surface snapshot timeout."); return false; } return true; } bool SurfaceDraw::DrawMasking(std::shared_ptr surfaceNode, Rect screenRect, Rect transparentRect) { int32_t screenHeight = static_cast(screenRect.height_); int32_t screenWidth = static_cast(screenRect.width_); int32_t transparentHeight = static_cast(transparentRect.height_); int32_t transparentWidth = static_cast(transparentRect.width_); sptr layer = GetLayer(surfaceNode); if (layer == nullptr) { WLOGFE("layer is nullptr"); return false; } sptr buffer = GetSurfaceBuffer(layer, screenWidth, screenHeight); if (buffer == nullptr || buffer->GetVirAddr() == nullptr) { return false; } auto addr = static_cast(buffer->GetVirAddr()); Drawing::Bitmap fullbitmap; Drawing::BitmapFormat fullBitmapFormat { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE }; fullbitmap.Build(screenWidth, screenHeight, fullBitmapFormat); Drawing::Canvas canvas; canvas.Bind(fullbitmap); canvas.Clear(0xFF000000); Drawing::Bitmap transBitmap; Drawing::BitmapFormat transBitmapFormat { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE }; transBitmap.Build(transparentWidth, transparentHeight, transBitmapFormat); transBitmap.ClearWithColor(0); canvas.DrawBitmap(transBitmap, static_cast(transparentRect.posX_), static_cast(transparentRect.posY_)); uint32_t addrSize = static_cast(screenWidth * screenHeight * IMAGE_BYTES_STRIDE); errno_t ret = memcpy_s(addr, addrSize, fullbitmap.GetPixels(), addrSize); if (ret != EOK) { WLOGFE("draw failed"); return false; } OHOS::BufferFlushConfig flushConfig = { .damage = { .w = buffer->GetWidth(), .h = buffer->GetHeight(), }, }; OHOS::SurfaceError surfaceRet = layer->FlushBuffer(buffer, -1, flushConfig); if (surfaceRet != OHOS::SurfaceError::SURFACE_ERROR_OK) { WLOGFE("draw masking FlushBuffer ret:%{public}s", SurfaceErrorStr(surfaceRet).c_str()); return false; } return true; } } // Rosen } // OHOS