• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "font_napi/js_typeface.h"
17 #include "js_drawing_utils.h"
18 
19 #ifdef ROSEN_OHOS
20 #include <parameters.h>
21 #endif
22 
23 #include "draw/color.h"
24 #include "effect/color_space.h"
25 #include "image/image_info.h"
26 #include "image/bitmap.h"
27 #include "image/image.h"
28 #include "rosen_text/font_collection.h"
29 #include "txt/platform.h"
30 
31 namespace OHOS::Rosen {
32 
33 #ifdef ROSEN_OHOS
34 bool JsDrawingTestUtils::closeDrawingTest_ =
35     std::atoi((OHOS::system::GetParameter("persist.sys.graphic.drawing.test", "0").c_str())) != 1;
36 #else
37 bool JsDrawingTestUtils::closeDrawingTest_ = true;
38 #endif
39 
40 namespace Drawing {
41 const char* const JSCOLOR[4] = {"alpha", "red", "green", "blue"};
42 
BindNativeFunction(napi_env env,napi_value object,const char * name,const char * moduleName,napi_callback func)43 void BindNativeFunction(napi_env env, napi_value object, const char* name, const char* moduleName, napi_callback func)
44 {
45     std::string fullName;
46     if (moduleName) {
47         fullName = moduleName;
48         fullName += '.';
49     }
50     fullName += name;
51     napi_value funcValue = nullptr;
52     napi_create_function(env, fullName.c_str(), fullName.size(), func, nullptr, &funcValue);
53     napi_set_named_property(env, object, fullName.c_str(), funcValue);
54 }
55 
CreateJsError(napi_env env,int32_t errCode,const std::string & message)56 napi_value CreateJsError(napi_env env, int32_t errCode, const std::string& message)
57 {
58     napi_value result = nullptr;
59     napi_create_error(env, CreateJsValue(env, errCode), CreateJsValue(env, message), &result);
60     return result;
61 }
62 
ConvertFromJsTextEncoding(napi_env env,TextEncoding & textEncoding,napi_value nativeType)63 bool ConvertFromJsTextEncoding(napi_env env, TextEncoding& textEncoding, napi_value nativeType)
64 {
65     napi_value type = nativeType;
66     if (type == nullptr) {
67         return false;
68     }
69     uint32_t resultValue = 0;
70     napi_get_value_uint32(env, type, &resultValue);
71 
72     switch (resultValue) {
73         case 0: // 0: TextEncoding::UTF8
74             textEncoding = TextEncoding::UTF8;
75             break;
76         case 1: // 1: TextEncoding::UTF16
77             textEncoding = TextEncoding::UTF16;
78             break;
79         case 2: // 2: TextEncoding::UTF32
80             textEncoding = TextEncoding::UTF32;
81             break;
82         case 3: // 3: TextEncoding::GLYPH_ID
83             textEncoding = TextEncoding::GLYPH_ID;
84             break;
85         default: // default: TextEncoding::UTF8
86             textEncoding = TextEncoding::UTF8;
87             break;
88     }
89     return true;
90 }
91 
NapiThrowError(napi_env env,DrawingErrorCode err,const std::string & message)92 napi_value NapiThrowError(napi_env env, DrawingErrorCode err, const std::string& message)
93 {
94     napi_throw(env, CreateJsError(env, static_cast<int32_t>(err), message));
95     return nullptr;
96 }
97 
98 static const char* g_argbString[4] = {"alpha", "red", "green", "blue"};
99 static const char* g_ltrbString[4] = {"left", "top", "right", "bottom"};
100 static const char* g_pointString[2] = {"x", "y"};
101 
ConvertFromJsColor(napi_env env,napi_value jsValue,int32_t * argb,size_t size)102 bool ConvertFromJsColor(napi_env env, napi_value jsValue, int32_t* argb, size_t size)
103 {
104     napi_value tempValue = nullptr;
105     for (size_t idx = 0; idx < size; idx++) {
106         int32_t* curChannel = argb + idx;
107         napi_get_named_property(env, jsValue, g_argbString[idx], &tempValue);
108         if (napi_get_value_int32(env, tempValue, curChannel) != napi_ok ||
109             *curChannel < 0 || *curChannel > Color::RGB_MAX) {
110             return false;
111         }
112     }
113     return true;
114 }
115 
ConvertFromJsColor4F(napi_env env,napi_value jsValue,double * argbF,size_t size)116 bool ConvertFromJsColor4F(napi_env env, napi_value jsValue, double* argbF, size_t size)
117 {
118     napi_value tempValue = nullptr;
119     for (size_t idx = 0; idx < size; idx++) {
120         double* curChannel = argbF + idx;
121         napi_get_named_property(env, jsValue, g_argbString[idx], &tempValue);
122         if (napi_get_value_double(env, tempValue, curChannel) != napi_ok) {
123             return false;
124         }
125     }
126     return true;
127 }
128 
ConvertFromAdaptHexJsColor(napi_env env,napi_value jsValue,Drawing::ColorQuad & jsColor)129 bool ConvertFromAdaptHexJsColor(napi_env env, napi_value jsValue, Drawing::ColorQuad& jsColor)
130 {
131     bool isJsColor = false;
132     napi_has_named_property(env, jsValue, JSCOLOR[0], &isJsColor);
133     if (isJsColor) {
134         int32_t argb[ARGC_FOUR] = {0};
135         if (!ConvertFromJsColor(env, jsValue, argb, ARGC_FOUR)) {
136             return false;
137         }
138         jsColor = Color::ColorQuadSetARGB(argb[ARGC_ZERO], argb[ARGC_ONE], argb[ARGC_TWO], argb[ARGC_THREE]);
139     } else {
140         if (napi_get_value_uint32(env, jsValue, &jsColor) != napi_ok) {
141             return false;
142         }
143     }
144     return true;
145 }
146 
ConvertFromAdaptJsColor4F(napi_env env,napi_value jsValue,Drawing::Color4f & jsColor4F)147 bool ConvertFromAdaptJsColor4F(napi_env env, napi_value jsValue, Drawing::Color4f& jsColor4F)
148 {
149     bool isJsColor4F = false;
150     napi_has_named_property(env, jsValue, JSCOLOR[0], &isJsColor4F);
151     if (!isJsColor4F) {
152         return false;
153     }
154 
155     double argbF[ARGC_FOUR] = {0};
156     if (!ConvertFromJsColor4F(env, jsValue, argbF, ARGC_FOUR)) {
157         return false;
158     }
159     jsColor4F.alphaF_ = static_cast<float>(argbF[ARGC_ZERO]);
160     jsColor4F.redF_ = static_cast<float>(argbF[ARGC_ONE]);
161     jsColor4F.greenF_ = static_cast<float>(argbF[ARGC_TWO]);
162     jsColor4F.blueF_ = static_cast<float>(argbF[ARGC_THREE]);
163 
164     return true;
165 }
166 
ConvertFromJsRect(napi_env env,napi_value jsValue,double * ltrb,size_t size)167 bool ConvertFromJsRect(napi_env env, napi_value jsValue, double* ltrb, size_t size)
168 {
169     napi_value tempValue = nullptr;
170     for (size_t idx = 0; idx < size; idx++) {
171         double* curEdge = ltrb + idx;
172         napi_get_named_property(env, jsValue, g_ltrbString[idx], &tempValue);
173         if (napi_get_value_double(env, tempValue, curEdge) != napi_ok) {
174             return false;
175         }
176     }
177     return true;
178 }
179 
ConvertFromJsIRect(napi_env env,napi_value jsValue,int32_t * ltrb,size_t size)180 bool ConvertFromJsIRect(napi_env env, napi_value jsValue, int32_t* ltrb, size_t size)
181 {
182     napi_value tempValue = nullptr;
183     for (size_t idx = 0; idx < size; idx++) {
184         int32_t* curEdge = ltrb + idx;
185         napi_get_named_property(env, jsValue, g_ltrbString[idx], &tempValue);
186         if (napi_get_value_int32(env, tempValue, curEdge) != napi_ok) {
187             return false;
188         }
189     }
190     return true;
191 }
192 
ConvertFromJsShadowFlag(napi_env env,napi_value src,ShadowFlags & shadowFlag,ShadowFlags defaultFlag)193 bool ConvertFromJsShadowFlag(napi_env env, napi_value src, ShadowFlags& shadowFlag, ShadowFlags defaultFlag)
194 {
195     if (src == nullptr) {
196         return false;
197     }
198     uint32_t value = 0;
199     if (!ConvertFromJsValue(env, src, value)) {
200         return false;
201     }
202     shadowFlag = defaultFlag;
203     if (value >= static_cast<uint32_t>(ShadowFlags::NONE) && value <= static_cast<uint32_t>(ShadowFlags::ALL)) {
204         shadowFlag = static_cast<ShadowFlags>(value);
205     }
206     return true;
207 }
208 
ConvertFromJsPoint3d(napi_env env,napi_value src,Point3 & point3d)209 bool ConvertFromJsPoint3d(napi_env env, napi_value src, Point3& point3d)
210 {
211     if (src == nullptr) {
212         return false;
213     }
214     napi_value tempValue = nullptr;
215     double x = 0.0;
216     double y = 0.0;
217     double z = 0.0;
218     napi_get_named_property(env, src, "x", &tempValue);
219     bool isXOk = ConvertFromJsValue(env, tempValue, x);
220     napi_get_named_property(env, src, "y", &tempValue);
221     bool isYOk = ConvertFromJsValue(env, tempValue, y);
222     napi_get_named_property(env, src, "z", &tempValue);
223     bool isZOk = ConvertFromJsValue(env, tempValue, z);
224     if (!(isXOk && isYOk && isZOk)) {
225         return false;
226     }
227     point3d = Point3(x, y, z);
228     return true;
229 }
230 
ConvertFromJsPoint(napi_env env,napi_value jsValue,double * point,size_t size)231 bool ConvertFromJsPoint(napi_env env, napi_value jsValue, double* point, size_t size)
232 {
233     if (point == nullptr) {
234         return false;
235     }
236     napi_value tempValue = nullptr;
237     for (size_t idx = 0; idx < size; idx++) {
238         double* curEdge = point + idx;
239         napi_get_named_property(env, jsValue, g_pointString[idx], &tempValue);
240         if (napi_get_value_double(env, tempValue, curEdge) != napi_ok) {
241             return false;
242         }
243     }
244     return true;
245 }
246 
ConvertFromJsPointsArray(napi_env env,napi_value array,Drawing::Point * points,uint32_t count)247 bool ConvertFromJsPointsArray(napi_env env, napi_value array, Drawing::Point* points, uint32_t count)
248 {
249     if (points == nullptr) {
250         return false;
251     }
252     for (uint32_t i = 0; i < count; i++)  {
253         napi_value tempPoint = nullptr;
254         if (napi_get_element(env, array, i, &tempPoint) != napi_ok) {
255             return false;
256         }
257         if (!GetDrawingPointFromJsValue(env, tempPoint, points[i])) {
258             return false;
259         }
260     }
261     return true;
262 }
263 
ConvertFromJsPointsArrayOffset(napi_env env,napi_value array,Drawing::Point * points,uint32_t count,uint32_t offset)264 bool ConvertFromJsPointsArrayOffset(napi_env env, napi_value array, Drawing::Point* points,
265     uint32_t count, uint32_t offset)
266 {
267     if (points == nullptr) {
268         return false;
269     }
270     for (uint32_t i = offset; i < offset + count; i++)  {
271         napi_value tempPoint = nullptr;
272         if (napi_get_element(env, array, i, &tempPoint) != napi_ok) {
273             return false;
274         }
275         if (!GetDrawingPointFromJsValue(env, tempPoint, points[i - offset])) {
276             return false;
277         }
278     }
279     return true;
280 }
281 
GetFontMetricsAndConvertToJsValue(napi_env env,FontMetrics * metrics)282 napi_value GetFontMetricsAndConvertToJsValue(napi_env env, FontMetrics* metrics)
283 {
284     napi_value objValue = nullptr;
285     napi_create_object(env, &objValue);
286     if (metrics != nullptr && objValue != nullptr) {
287         napi_set_named_property(env, objValue, "top", CreateJsNumber(env, metrics->fTop));
288         napi_set_named_property(env, objValue, "ascent", CreateJsNumber(env, metrics->fAscent));
289         napi_set_named_property(env, objValue, "descent", CreateJsNumber(env, metrics->fDescent));
290         napi_set_named_property(env, objValue, "bottom", CreateJsNumber(env, metrics->fBottom));
291         napi_set_named_property(env, objValue, "leading", CreateJsNumber(env, metrics->fLeading));
292         napi_set_named_property(env, objValue, "flags", CreateJsNumber(env, metrics->fFlags));
293         napi_set_named_property(env, objValue, "avgCharWidth", CreateJsNumber(env, metrics->fAvgCharWidth));
294         napi_set_named_property(env, objValue, "maxCharWidth", CreateJsNumber(env, metrics->fMaxCharWidth));
295         napi_set_named_property(env, objValue, "xMin", CreateJsNumber(env, metrics->fXMin));
296         napi_set_named_property(env, objValue, "xMax", CreateJsNumber(env, metrics->fXMax));
297         napi_set_named_property(env, objValue, "xHeight", CreateJsNumber(env, metrics->fXHeight));
298         napi_set_named_property(env, objValue, "capHeight", CreateJsNumber(env, metrics->fCapHeight));
299         napi_set_named_property(env, objValue, "underlineThickness", CreateJsNumber(env,
300             metrics->fUnderlineThickness));
301         napi_set_named_property(env, objValue, "underlinePosition", CreateJsNumber(env,
302             metrics->fUnderlinePosition));
303         napi_set_named_property(env, objValue, "strikethroughThickness", CreateJsNumber(env,
304             metrics->fStrikeoutThickness));
305         napi_set_named_property(env, objValue, "strikethroughPosition", CreateJsNumber(env,
306             metrics->fStrikeoutPosition));
307     }
308     return objValue;
309 }
310 
311 #if defined(ROSEN_OHOS) || defined(ROSEN_ARKUI_X)
ColorSpaceToDrawingColorSpace(Media::ColorSpace colorSpace)312 std::shared_ptr<Drawing::ColorSpace> ColorSpaceToDrawingColorSpace(Media::ColorSpace colorSpace)
313 {
314     switch (colorSpace) {
315         case Media::ColorSpace::DISPLAY_P3:
316             return Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB, Drawing::CMSMatrixType::DCIP3);
317         case Media::ColorSpace::LINEAR_SRGB:
318             return Drawing::ColorSpace::CreateSRGBLinear();
319         case Media::ColorSpace::SRGB:
320             return Drawing::ColorSpace::CreateSRGB();
321         default:
322             return Drawing::ColorSpace::CreateSRGB();
323     }
324 }
325 
PixelFormatToDrawingColorType(Media::PixelFormat pixelFormat)326 Drawing::ColorType PixelFormatToDrawingColorType(Media::PixelFormat pixelFormat)
327 {
328     switch (pixelFormat) {
329         case Media::PixelFormat::RGB_565:
330             return Drawing::ColorType::COLORTYPE_RGB_565;
331         case Media::PixelFormat::RGBA_8888:
332             return Drawing::ColorType::COLORTYPE_RGBA_8888;
333         case Media::PixelFormat::BGRA_8888:
334             return Drawing::ColorType::COLORTYPE_BGRA_8888;
335         case Media::PixelFormat::ALPHA_8:
336             return Drawing::ColorType::COLORTYPE_ALPHA_8;
337         case Media::PixelFormat::RGBA_F16:
338             return Drawing::ColorType::COLORTYPE_RGBA_F16;
339         case Media::PixelFormat::UNKNOWN:
340         case Media::PixelFormat::ARGB_8888:
341         case Media::PixelFormat::RGB_888:
342         case Media::PixelFormat::NV21:
343         case Media::PixelFormat::NV12:
344         case Media::PixelFormat::CMYK:
345         default:
346             return Drawing::ColorType::COLORTYPE_UNKNOWN;
347     }
348 }
349 
AlphaTypeToDrawingAlphaType(Media::AlphaType alphaType)350 Drawing::AlphaType AlphaTypeToDrawingAlphaType(Media::AlphaType alphaType)
351 {
352     switch (alphaType) {
353         case Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
354             return Drawing::AlphaType::ALPHATYPE_UNKNOWN;
355         case Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
356             return Drawing::AlphaType::ALPHATYPE_OPAQUE;
357         case Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
358             return Drawing::AlphaType::ALPHATYPE_PREMUL;
359         case Media::AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
360             return Drawing::AlphaType::ALPHATYPE_UNPREMUL;
361         default:
362             return Drawing::AlphaType::ALPHATYPE_UNKNOWN;
363     }
364 }
365 
ExtracetDrawingBitmap(std::shared_ptr<Media::PixelMap> pixelMap,Drawing::Bitmap & bitmap)366 bool ExtracetDrawingBitmap(std::shared_ptr<Media::PixelMap> pixelMap, Drawing::Bitmap& bitmap)
367 {
368     if (!pixelMap) {
369         ROSEN_LOGE("Drawing_napi ::pixelMap fail");
370         return false;
371     }
372     Media::ImageInfo imageInfo;
373     pixelMap->GetImageInfo(imageInfo);
374     Drawing::ImageInfo drawingImageInfo { imageInfo.size.width, imageInfo.size.height,
375         PixelFormatToDrawingColorType(imageInfo.pixelFormat), AlphaTypeToDrawingAlphaType(imageInfo.alphaType),
376         ColorSpaceToDrawingColorSpace(imageInfo.colorSpace) };
377     bitmap.Build(drawingImageInfo, pixelMap->GetRowStride());
378     bitmap.SetPixels(const_cast<void*>(reinterpret_cast<const void*>(pixelMap->GetPixels())));
379     return true;
380 }
381 
382 struct PixelMapReleaseContext {
PixelMapReleaseContextOHOS::Rosen::Drawing::PixelMapReleaseContext383     explicit PixelMapReleaseContext(std::shared_ptr<Media::PixelMap> pixelMap) : pixelMap_(pixelMap) {}
384 
~PixelMapReleaseContextOHOS::Rosen::Drawing::PixelMapReleaseContext385     ~PixelMapReleaseContext()
386     {
387         pixelMap_ = nullptr;
388     }
389 
390 private:
391     std::shared_ptr<Media::PixelMap> pixelMap_;
392 };
393 
PixelMapReleaseProc(const void *,void * context)394 static void PixelMapReleaseProc(const void* /* pixels */, void* context)
395 {
396     PixelMapReleaseContext* ctx = static_cast<PixelMapReleaseContext*>(context);
397     if (ctx) {
398         delete ctx;
399         ctx = nullptr;
400     }
401 }
402 
ExtractDrawingImage(std::shared_ptr<Media::PixelMap> pixelMap)403 std::shared_ptr<Drawing::Image> ExtractDrawingImage(std::shared_ptr<Media::PixelMap> pixelMap)
404 {
405     if (!pixelMap) {
406         ROSEN_LOGE("Drawing_napi::pixelMap fail");
407         return nullptr;
408     }
409     Media::ImageInfo imageInfo;
410     pixelMap->GetImageInfo(imageInfo);
411     Drawing::ImageInfo drawingImageInfo { imageInfo.size.width, imageInfo.size.height,
412         PixelFormatToDrawingColorType(imageInfo.pixelFormat), AlphaTypeToDrawingAlphaType(imageInfo.alphaType),
413         ColorSpaceToDrawingColorSpace(imageInfo.colorSpace) };
414     Drawing::Pixmap imagePixmap(
415         drawingImageInfo, reinterpret_cast<const void*>(pixelMap->GetPixels()), pixelMap->GetRowStride());
416     PixelMapReleaseContext* releaseContext = new PixelMapReleaseContext(pixelMap);
417     auto image = Drawing::Image::MakeFromRaster(imagePixmap, PixelMapReleaseProc, releaseContext);
418     if (!image) {
419         ROSEN_LOGE("Drawing_napi :RSPixelMapUtil::ExtractDrawingImage fail");
420         delete releaseContext;
421         releaseContext = nullptr;
422     }
423     return image;
424 }
425 #endif
426 
GetThemeFont(std::shared_ptr<Font> font)427 std::shared_ptr<Font> GetThemeFont(std::shared_ptr<Font> font)
428 {
429     std::shared_ptr<FontMgr> fontMgr = GetFontMgr(font);
430     if (fontMgr == nullptr) {
431         return nullptr;
432     }
433     std::shared_ptr<Typeface> themeTypeface =
434         std::shared_ptr<Typeface>(fontMgr->MatchFamilyStyle(SPText::OHOS_THEME_FONT, FontStyle()));
435     if (themeTypeface == nullptr) {
436         return nullptr;
437     }
438     std::shared_ptr<Font> themeFont = std::make_shared<Font>(*font);
439     themeFont->SetTypeface(themeTypeface);
440     return themeFont;
441 }
442 
MatchThemeFont(std::shared_ptr<Font> font,int32_t unicode)443 std::shared_ptr<Font> MatchThemeFont(std::shared_ptr<Font> font, int32_t unicode)
444 {
445     std::shared_ptr<FontMgr> fontMgr = GetFontMgr(font);
446     if (fontMgr == nullptr) {
447         return nullptr;
448     }
449     auto themeFamilies = SPText::DefaultFamilyNameMgr::GetInstance().GetThemeFontFamilies();
450     std::shared_ptr<Drawing::Font> themeFont = std::make_shared<Drawing::Font>(*font);
451     for (const auto& family : themeFamilies) {
452         std::shared_ptr<Drawing::Typeface> themeTypeface =
453             std::shared_ptr<Drawing::Typeface>(fontMgr->MatchFamilyStyle(family.c_str(), FontStyle()));
454         themeFont->SetTypeface(themeTypeface);
455         if (themeFont->UnicharToGlyph(unicode)) {
456             return themeFont;
457         }
458     }
459     return nullptr;
460 }
461 
GetFontMgr(std::shared_ptr<Font> font)462 std::shared_ptr<FontMgr> GetFontMgr(std::shared_ptr<Font> font)
463 {
464     if (!font->IsThemeFontFollowed() || font->GetTypeface() != JsTypeface::GetZhCnTypeface()) {
465         return nullptr;
466     }
467 
468     std::shared_ptr<FontCollection> fontCollection = FontCollection::Create();
469     if (fontCollection == nullptr) {
470         return nullptr;
471     }
472     std::shared_ptr<FontMgr> fontMgr = fontCollection->GetFontMgr();
473     if (fontMgr == nullptr) {
474         return nullptr;
475     }
476     return fontMgr;
477 }
478 
MakeFontFeaturesFromJsArray(napi_env env,std::shared_ptr<DrawingFontFeatures> features,uint32_t size,napi_value & array)479 void MakeFontFeaturesFromJsArray(napi_env env, std::shared_ptr<DrawingFontFeatures> features,
480     uint32_t size, napi_value& array)
481 {
482     features->clear();
483 
484     for (uint32_t i = 0; i < size; ++i) {
485         napi_value tempNumber = nullptr;
486         napi_status status = napi_get_element(env, array, i, &tempNumber);
487         if (status != napi_ok || tempNumber == nullptr) {
488             continue;
489         }
490         std::string name;
491         napi_value tempValue = nullptr;
492         status = napi_get_named_property(env, tempNumber, "name", &tempValue);
493         if (status != napi_ok || tempValue == nullptr) {
494             continue;
495         }
496         if (!ConvertFromJsValue(env, tempValue, name)) {
497             continue;
498         }
499         double value = 0.0;
500         status = napi_get_named_property(env, tempNumber, "value", &tempValue);
501         if (status != napi_ok || tempValue == nullptr) {
502             continue;
503         }
504         if (!ConvertFromJsValue(env, tempValue, value)) {
505             continue;
506         }
507         features->push_back({{name, value}});
508     }
509 }
510 } // namespace Drawing
511 } // namespace OHOS::Rosen
512