• 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 "core/components_ng/pattern/canvas/offscreen_canvas_paint_method.h"
17 
18 #ifndef ACE_UNITTEST
19 #ifdef USE_NEW_SKIA
20 #include "src/base/SkBase64.h"
21 #else
22 #include "include/utils/SkBase64.h"
23 #endif
24 #include "core/components/common/painter/rosen_decoration_painter.h"
25 #include "core/components/font/constants_converter.h"
26 #include "core/components/font/rosen_font_collection.h"
27 #endif
28 
29 #include "base/i18n/localization.h"
30 #include "core/common/container.h"
31 #include "core/components_ng/pattern/canvas/custom_paint_util.h"
32 
33 namespace OHOS::Ace::NG {
34 constexpr Dimension DEFAULT_FONT_SIZE = 14.0_px;
OffscreenCanvasPaintMethod(int32_t width,int32_t height)35 OffscreenCanvasPaintMethod::OffscreenCanvasPaintMethod(int32_t width, int32_t height)
36 {
37     antiAlias_ = false;
38     matrix_.Reset();
39     width_ = width;
40     height_ = height;
41     lastLayoutSize_.SetWidth(static_cast<float>(width));
42     lastLayoutSize_.SetHeight(static_cast<float>(height));
43     InitBitmap();
44     // The default value of the font size in canvas is 14px.
45     SetFontSize(DEFAULT_FONT_SIZE);
46     if (apiVersion_ >= static_cast<int32_t>(PlatformVersion::VERSION_EIGHTEEN)) {
47         isPathChanged_ = false;
48         isPath2dChanged_ = false;
49     }
50 }
51 
InitBitmap()52 void OffscreenCanvasPaintMethod::InitBitmap()
53 {
54     RSBitmapFormat bitmapFormat = { RSColorType::COLORTYPE_RGBA_8888, RSAlphaType::ALPHATYPE_UNPREMUL };
55     bool ret = bitmap_.Build(width_, height_, bitmapFormat);
56     if (!ret) {
57         TAG_LOGE(AceLogTag::ACE_CANVAS, "The width and height exceed the limit size.");
58         return;
59     }
60     bitmap_.ClearWithColor(RSColor::COLOR_TRANSPARENT);
61     bitmapSize_ = bitmap_.ComputeByteSize();
62     rsCanvas_ = std::make_unique<RSCanvas>();
63     rsCanvas_->Bind(bitmap_);
64 }
65 
TransferToImageBitmap()66 RefPtr<PixelMap> OffscreenCanvasPaintMethod::TransferToImageBitmap()
67 {
68 #ifdef PIXEL_MAP_SUPPORTED
69     OHOS::Media::InitializationOptions options;
70     options.alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
71     options.pixelFormat = OHOS::Media::PixelFormat::RGBA_8888;
72     options.scaleMode = OHOS::Media::ScaleMode::CENTER_CROP;
73     options.size.width = width_;
74     options.size.height = height_;
75     options.editable = true;
76     auto pixelMap = Ace::PixelMap::Create(OHOS::Media::PixelMap::Create(options));
77     CHECK_NULL_RETURN(pixelMap, nullptr);
78     std::shared_ptr<Ace::ImageData> imageData = std::make_shared<Ace::ImageData>();
79     imageData->pixelMap = pixelMap;
80     imageData->dirtyX = 0.0f;
81     imageData->dirtyY = 0.0f;
82     imageData->dirtyWidth = width_;
83     imageData->dirtyHeight = height_;
84     GetImageData(imageData);
85     return pixelMap;
86 #else
87     return nullptr;
88 #endif
89 }
90 
Reset()91 void OffscreenCanvasPaintMethod::Reset()
92 {
93     matrix_.Reset();
94     ResetStates();
95     InitBitmap();
96 }
97 
GetSystemDirection()98 TextDirection OffscreenCanvasPaintMethod::GetSystemDirection()
99 {
100     return AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
101 }
102 
UpdateSize(int32_t width,int32_t height)103 void OffscreenCanvasPaintMethod::UpdateSize(int32_t width, int32_t height)
104 {
105     width_ = width;
106     height_ = height;
107     lastLayoutSize_.SetWidth(static_cast<float>(width));
108     lastLayoutSize_.SetHeight(static_cast<float>(height));
109     Reset();
110 }
111 
DrawPixelMap(RefPtr<PixelMap> pixelMap,const Ace::CanvasImage & canvasImage)112 void OffscreenCanvasPaintMethod::DrawPixelMap(RefPtr<PixelMap> pixelMap, const Ace::CanvasImage& canvasImage)
113 {
114 #ifndef ACE_UNITTEST
115     // get Image form pixelMap
116     CHECK_NULL_VOID(pixelMap);
117     auto rsBitmapFormat = Ace::ImageProvider::MakeRSBitmapFormatFromPixelMap(pixelMap);
118     auto rsBitmap = std::make_shared<RSBitmap>();
119     bool ret = rsBitmap->Build(pixelMap->GetWidth(), pixelMap->GetHeight(), rsBitmapFormat, pixelMap->GetRowStride());
120     if (!ret) {
121         TAG_LOGE(AceLogTag::ACE_CANVAS, "The width and height exceed the limit size.");
122         return;
123     }
124     rsBitmap->SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixelMap->GetPixels())));
125 
126     // Step2: Create Image and draw it, using gpu or cpu
127     auto image = std::make_shared<RSImage>();
128     CHECK_NULL_VOID(image->BuildFromBitmap(*rsBitmap));
129     DrawImageInternal(canvasImage, image);
130 #endif
131 }
132 
GetImageData(double left,double top,double width,double height)133 std::unique_ptr<Ace::ImageData> OffscreenCanvasPaintMethod::GetImageData(
134     double left, double top, double width, double height)
135 {
136     double dirtyWidth = std::abs(width);
137     double dirtyHeight = std::abs(height);
138     double scaledLeft = left + std::min(width, 0.0);
139     double scaledTop = top + std::min(height, 0.0);
140     // copy the bitmap to tempCanvas
141     RSBitmapFormat format { RSColorType::COLORTYPE_BGRA_8888, RSAlphaType::ALPHATYPE_PREMUL };
142     int32_t size = dirtyWidth * dirtyHeight;
143     auto srcRect =
144         RSRect(scaledLeft, scaledTop, dirtyWidth + scaledLeft, dirtyHeight + scaledTop);
145     auto dstRect = RSRect(0.0, 0.0, dirtyWidth, dirtyHeight);
146     RSBitmap tempCache;
147     tempCache.Build(dirtyWidth, dirtyHeight, format);
148     RSCanvas tempCanvas;
149     tempCanvas.Bind(tempCache);
150     RSImage rsImage;
151     rsImage.BuildFromBitmap(bitmap_);
152     tempCanvas.DrawImageRect(
153         rsImage, srcRect, dstRect, RSSamplingOptions(), RSSrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
154     // write color
155     uint8_t* pixels = static_cast<uint8_t*>(tempCache.GetPixels());
156     std::unique_ptr<Ace::ImageData> imageData = std::make_unique<Ace::ImageData>();
157     imageData->dirtyWidth = dirtyWidth;
158     imageData->dirtyHeight = dirtyHeight;
159     // a pixel include 4 data blue, green, red, alpha
160     for (int i = 0; i < size * 4; i += 4) {
161         auto blue = pixels[i];
162         auto green = pixels[i + 1];
163         auto red = pixels[i + 2];
164         auto alpha = pixels[i + 3];
165         imageData->data.emplace_back(Color::FromARGB(alpha, red, green, blue).GetValue());
166     }
167     return imageData;
168 }
169 
GetImageData(const std::shared_ptr<Ace::ImageData> & imageData)170 void OffscreenCanvasPaintMethod::GetImageData(const std::shared_ptr<Ace::ImageData>& imageData)
171 {
172     int32_t dirtyWidth = std::abs(imageData->dirtyWidth);
173     int32_t dirtyHeight = std::abs(imageData->dirtyHeight);
174     double scaledLeft = imageData->dirtyX + std::min(imageData->dirtyWidth, 0);
175     double scaledTop = imageData->dirtyY + std::min(imageData->dirtyHeight, 0);
176     double dx = std::min(scaledLeft, 0.0);
177     double dy = std::min(scaledTop, 0.0);
178     // copy the bitmap to tempCanvas
179     RSBitmap subBitmap;
180     auto rect = RSRect(scaledLeft, scaledTop, dirtyWidth + scaledLeft, dirtyHeight + scaledTop);
181     bool ret = bitmap_.ExtractSubset(subBitmap, rect);
182     if (!ret) {
183         return;
184     }
185     auto pixelMap = imageData->pixelMap;
186     CHECK_NULL_VOID(pixelMap);
187     auto* rawData = pixelMap->GetWritablePixels();
188     CHECK_NULL_VOID(rawData);
189     RSImageInfo imageInfo =
190         RSImageInfo(dirtyWidth, dirtyHeight, RSColorType::COLORTYPE_RGBA_8888, RSAlphaType::ALPHATYPE_PREMUL);
191     subBitmap.ReadPixels(imageInfo, rawData, dirtyWidth * imageInfo.GetBytesPerPixel(), dx, dy);
192 }
193 
ToDataURL(const std::string & type,const double quality)194 std::string OffscreenCanvasPaintMethod::ToDataURL(const std::string& type, const double quality)
195 {
196 #ifndef ACE_UNITTEST
197     std::string mimeType = GetMimeType(type);
198     // Quality needs to be between 0.0 and 1.0 for MimeType jpeg and webp
199     double qua = GetQuality(mimeType, quality);
200     auto imageInfo = SkImageInfo::Make(width_, height_, SkColorType::kBGRA_8888_SkColorType,
201         (mimeType == IMAGE_JPEG) ? SkAlphaType::kOpaque_SkAlphaType : SkAlphaType::kUnpremul_SkAlphaType);
202     RSBitmap tempCache;
203     tempCache.Build(width_, height_,
204         { RSColorType::COLORTYPE_BGRA_8888,
205             (mimeType == IMAGE_JPEG) ? RSAlphaType::ALPHATYPE_OPAQUE : RSAlphaType::ALPHATYPE_UNPREMUL });
206     RSCanvas tempCanvas;
207     tempCanvas.Bind(tempCache);
208     tempCanvas.Clear(RSColor::COLOR_TRANSPARENT);
209     tempCanvas.Scale(1.0, 1.0);
210     tempCanvas.DrawBitmap(bitmap_, 0.0f, 0.0f);
211     RSPixmap rsSrc;
212     bool success = tempCache.PeekPixels(rsSrc);
213     CHECK_NULL_RETURN(success, UNSUPPORTED);
214     SkPixmap src { imageInfo, rsSrc.GetAddr(), rsSrc.GetRowBytes() };
215     SkDynamicMemoryWStream dst;
216     success = EncodeImage(mimeType, qua, src, dst);
217     CHECK_NULL_RETURN(success, UNSUPPORTED);
218     auto result = dst.detachAsData();
219     CHECK_NULL_RETURN(result, UNSUPPORTED);
220     size_t len = SkBase64::Encode(result->data(), result->size(), nullptr);
221     if (len > MAX_LENGTH) {
222         return UNSUPPORTED;
223     }
224     SkString info(len);
225 #ifdef USE_NEW_SKIA
226     SkBase64::Encode(result->data(), result->size(), info.data());
227 #else
228     SkBase64::Encode(result->data(), result->size(), info.writable_str());
229 #endif
230     return std::string(URL_PREFIX).append(mimeType).append(URL_SYMBOL).append(info.c_str());
231 #else
232     return UNSUPPORTED;
233 #endif
234 }
235 
GetTransform() const236 TransformParam OffscreenCanvasPaintMethod::GetTransform() const
237 {
238     TransformParam param;
239     CHECK_NULL_RETURN(rsCanvas_, param);
240     RSMatrix matrix = rsCanvas_->GetTotalMatrix();
241     param.scaleX = matrix.Get(RSMatrix::SCALE_X);
242     param.scaleY = matrix.Get(RSMatrix::SCALE_Y);
243     param.skewX = matrix.Get(RSMatrix::SKEW_X);
244     param.skewY = matrix.Get(RSMatrix::SKEW_Y);
245     param.translateX = matrix.Get(RSMatrix::TRANS_X);
246     param.translateY = matrix.Get(RSMatrix::TRANS_Y);
247     return param;
248 }
249 
GetLineDash() const250 LineDashParam OffscreenCanvasPaintMethod::GetLineDash() const
251 {
252     return state_.strokeState.GetLineDash();
253 }
254 
255 #ifndef ACE_UNITTEST
ConvertTxtStyle(const TextStyle & textStyle,Rosen::TextStyle & txtStyle)256 void OffscreenCanvasPaintMethod::ConvertTxtStyle(const TextStyle& textStyle, Rosen::TextStyle& txtStyle)
257 {
258     Constants::ConvertTxtStyle(textStyle, txtStyle);
259 }
260 #endif
261 } // namespace OHOS::Ace::NG
262