1 /*
2 * Copyright (c) 2022-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 "core/components_ng/svg/parse/svg_graphic.h"
17
18 #include "core/common/container.h"
19 #include "core/components_ng/svg/parse/svg_linear_gradient.h"
20 #include "core/components_ng/svg/parse/svg_pattern.h"
21 #include "core/components_ng/svg/parse/svg_radial_gradient.h"
22 #include "core/components_ng/svg/parse/svg_transform.h"
23 namespace OHOS::Ace::NG {
24 namespace {
25 constexpr double HALF = 0.5;
26 } // namespace
27
OnDraw(RSCanvas & canvas,const Size & layout,const std::optional<Color> & color)28 void SvgGraphic::OnDraw(RSCanvas& canvas, const Size& layout, const std::optional<Color>& color)
29 {
30 fillBrush_.Reset();
31 strokePen_.Reset();
32 path_ = AsPath(layout); // asPath override by graphic tag
33 UpdateFillGradient(layout);
34 if (UpdateFillStyle(color)) {
35 OnGraphicFill();
36 }
37 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
38 UpdateStrokeGradient(layout);
39 if (UpdateStrokeStyle()) {
40 OnGraphicStroke();
41 }
42 if (!fillState_.GetHref().empty()) {
43 auto svgContext = svgContext_.Upgrade();
44 CHECK_NULL_VOID(svgContext);
45 auto refSvgNode = svgContext->GetSvgNodeById(fillState_.GetHref());
46 CHECK_NULL_VOID(refSvgNode);
47 refSvgNode->Draw(canvas, layout, color);
48 }
49 return;
50 }
51 if (!fillState_.GetHref().empty()) {
52 auto svgContext = svgContext_.Upgrade();
53 CHECK_NULL_VOID(svgContext);
54 auto refSvgNode = svgContext->GetSvgNodeById(fillState_.GetHref());
55 CHECK_NULL_VOID(refSvgNode);
56 auto bounds = AsPath(layout).GetBounds();
57 Rect rect = Rect { bounds.GetLeft(), bounds.GetTop(), bounds.GetWidth(), bounds.GetHeight() };
58 auto svgpattern = AceType::DynamicCast<SvgPattern>(refSvgNode);
59 CHECK_NULL_VOID(svgpattern);
60 svgpattern->SetBoundingBoxRect(rect);
61 refSvgNode->Draw(canvas, layout, color);
62 }
63 UpdateStrokeGradient(layout);
64 if (UpdateStrokeStyle()) {
65 OnGraphicStroke();
66 }
67 }
68
OnDraw(RSCanvas & canvas,const SvgLengthScaleRule & lengthRule)69 void SvgGraphic::OnDraw(RSCanvas& canvas, const SvgLengthScaleRule& lengthRule)
70 {
71 RSRecordingPath path = AsPath(lengthRule); // asPath override by graphic tag
72 if (!path.IsValid()) {
73 return;
74 }
75 auto bounds = path.GetBounds();
76 Rect boundingRect(bounds.GetLeft(), bounds.GetTop(), bounds.GetWidth(), bounds.GetHeight());
77 SvgCoordinateSystemContext svgCoordinateSystemContext(boundingRect, lengthRule.GetViewPort());
78 svgCoordinateSystemContext.SetUseFillColor(lengthRule.UseFillColor());
79 auto fillType = GetFillType();
80 if (fillType != PaintType::NONE) {
81 OnGraphicFill(canvas, svgCoordinateSystemContext, path, fillType);
82 }
83 auto strokeType = GetStrokeType();
84 if (GreatNotEqual(attributes_.strokeState.GetLineWidth().Value(), 0.0) &&
85 strokeType != PaintType::NONE) {
86 OnGraphicStroke(canvas, svgCoordinateSystemContext, path, strokeType);
87 }
88 }
89
DumpDrawPathInfo(const RSRecordingPath & path)90 void SvgGraphic::DumpDrawPathInfo(const RSRecordingPath& path)
91 {
92 auto svgContext = svgContext_.Upgrade();
93 if (!svgContext || svgContext->GetHasRecordedPath()) {
94 return;
95 }
96 std::string dumpInfo = "";
97 path.Dump(dumpInfo);
98 svgContext->SetSvgDrawPathInfoDump(std::move(dumpInfo));
99 }
100
GetFillType()101 PaintType SvgGraphic::GetFillType()
102 {
103 // fill="none" in this shape, return PaintType::None
104 if (attributes_.fillState.IsFillNone()) {
105 return PaintType::NONE;
106 }
107 // fill=pattern, gradient in this shape
108 if (!attributes_.fillState.GetHref().empty()) {
109 return GetHrefType(attributes_.fillState.GetHref());
110 }
111 // fill="color" case
112 if (attributes_.fillState.HasColor()) {
113 return PaintType::COLOR;
114 }
115 // this shape fill has no color, Href, gradient, but gradient inherit from parent
116 auto& gradient = attributes_.fillState.GetGradient();
117 if (gradient.has_value()) {
118 auto href = gradient->GetHref();
119 if (!href.empty()) {
120 attributes_.fillState.SetHref(href);
121 return GetHrefType(attributes_.fillState.GetHref());
122 }
123 }
124 //By default No Fill in this shape and inherited from parent, apply the default color
125 return PaintType::COLOR;
126 }
127
CheckHrefPattern()128 bool SvgGraphic::CheckHrefPattern()
129 {
130 auto svgContext = svgContext_.Upgrade();
131 CHECK_NULL_RETURN(svgContext, false);
132 auto refSvgNode = svgContext->GetSvgNodeById(fillState_.GetHref());
133 CHECK_NULL_RETURN(refSvgNode, false);
134 return AceType::InstanceOf<SvgPattern>(refSvgNode);
135 }
136
GetHrefType(const std::string & href)137 PaintType SvgGraphic::GetHrefType(const std::string& href)
138 {
139 auto svgContext = svgContext_.Upgrade();
140 CHECK_NULL_RETURN(svgContext, PaintType::NONE);
141 auto refSvgNode = svgContext->GetSvgNodeById(href);
142 CHECK_NULL_RETURN(refSvgNode, PaintType::NONE);
143 if (AceType::InstanceOf<SvgPattern>(refSvgNode)) {
144 return PaintType::PATTERN;
145 }
146 if (AceType::InstanceOf<SvgLinearGradient>(refSvgNode)) {
147 return PaintType::LINEAR_GRADIENT;
148 }
149 if (AceType::InstanceOf<SvgRadialGradient>(refSvgNode)) {
150 return PaintType::RADIAL_GRADIENT;
151 }
152 return PaintType::NONE;
153 }
154
SetLinearGradient(const Size & viewPort,OHOS::Ace::Gradient & gradient)155 void SvgGraphic::SetLinearGradient(const Size& viewPort, OHOS::Ace::Gradient& gradient)
156 {
157 auto bounds = AsBounds(viewPort);
158 auto width = bounds.Width();
159 auto height = bounds.Height();
160
161 const auto& linearGradient = gradient.GetLinearGradient();
162 auto gradientInfo = OHOS::Ace::LinearGradientInfo();
163
164 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FOURTEEN) &&
165 NearEqual(linearGradient.x1, linearGradient.y1) && NearEqual(linearGradient.x2, linearGradient.y2)) {
166 RectifyTargetSize(bounds, width, height);
167 }
168
169 gradientInfo.x1 = linearGradient.x1 ? ConvertDimensionToPx(linearGradient.x1.value(), width) : 0.0;
170 if (linearGradient.x1 && linearGradient.x1.value().Unit() == DimensionUnit::PERCENT) {
171 gradientInfo.x1 += bounds.Left();
172 }
173 gradientInfo.y1 = linearGradient.y1 ? ConvertDimensionToPx(linearGradient.y1.value(), height) : 0.0;
174 if (linearGradient.y1 && linearGradient.y1.value().Unit() == DimensionUnit::PERCENT) {
175 gradientInfo.y1 += bounds.Top();
176 }
177 gradientInfo.x2 = ConvertDimensionToPx((linearGradient.x2 ? linearGradient.x2.value() : 1.0_pct), width);
178 if (linearGradient.x2 && linearGradient.x2.value().Unit() == DimensionUnit::PERCENT) {
179 gradientInfo.x2 += bounds.Left();
180 }
181 gradientInfo.y2 = linearGradient.y2 ? ConvertDimensionToPx(linearGradient.y2.value(), height) : 0.0;
182 if (linearGradient.y2 && linearGradient.y2.value().Unit() == DimensionUnit::PERCENT) {
183 gradientInfo.y2 += bounds.Top();
184 }
185
186 gradient.SetLinearGradientInfo(gradientInfo);
187 }
188
SetRadialGradient(const Size & viewPort,OHOS::Ace::Gradient & gradient)189 void SvgGraphic::SetRadialGradient(const Size& viewPort, OHOS::Ace::Gradient& gradient)
190 {
191 auto bounds = AsBounds(viewPort);
192 auto width = bounds.Width();
193 auto height = bounds.Height();
194
195 const auto& radialGradient = gradient.GetRadialGradient();
196 auto gradientInfo = OHOS::Ace::RadialGradientInfo();
197
198 gradientInfo.r = ConvertDimensionToPx(radialGradient.radialHorizontalSize ?
199 Dimension(radialGradient.radialHorizontalSize.value().Value(),
200 radialGradient.radialHorizontalSize.value().Unit()) : 0.5_pct, std::max(width, height));
201 gradientInfo.cx = ConvertDimensionToPx(radialGradient.radialCenterX ?
202 Dimension(radialGradient.radialCenterX.value().Value(),
203 radialGradient.radialCenterX.value().Unit()) : 0.5_pct, width) + bounds.Left();
204 gradientInfo.cy = ConvertDimensionToPx(radialGradient.radialCenterY ?
205 Dimension(radialGradient.radialCenterY.value().Value(),
206 radialGradient.radialCenterY.value().Unit()) : 0.5_pct, height) + bounds.Top();
207 if (radialGradient.fRadialCenterX && radialGradient.fRadialCenterX->IsValid()) {
208 gradientInfo.fx = ConvertDimensionToPx(radialGradient.fRadialCenterX.value(), width) + bounds.Left();
209 } else {
210 gradientInfo.fx = gradientInfo.cx;
211 }
212 if (radialGradient.fRadialCenterY && radialGradient.fRadialCenterY->IsValid()) {
213 gradientInfo.fy = ConvertDimensionToPx(radialGradient.fRadialCenterY.value(), height) + bounds.Top();
214 } else {
215 gradientInfo.fy = gradientInfo.cy;
216 }
217 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
218 gradientInfo.r = ConvertDimensionToPx(radialGradient.radialHorizontalSize ?
219 Dimension(radialGradient.radialHorizontalSize.value().Value(),
220 radialGradient.radialHorizontalSize.value().Unit()) : 0.5_pct, std::sqrt(width * height));
221 gradientInfo.fy = gradientInfo.fx;
222 } else {
223 gradientInfo.r = ConvertDimensionToPx(radialGradient.radialHorizontalSize ?
224 Dimension(radialGradient.radialHorizontalSize.value().Value(),
225 radialGradient.radialHorizontalSize.value().Unit()) : 0.5_pct, std::max(width, height));
226 }
227 gradient.SetRadialGradientInfo(gradientInfo);
228 }
229
UpdateFillGradient(const Size & viewPort)230 void SvgGraphic::UpdateFillGradient(const Size& viewPort)
231 {
232 fillState_ = attributes_.fillState;
233 auto& gradient = fillState_.GetGradient();
234 CHECK_NULL_VOID(gradient);
235 if (gradient->GetType() == OHOS::Ace::GradientType::LINEAR) {
236 SetLinearGradient(viewPort, gradient.value());
237 } else if (gradient->GetType() == OHOS::Ace::GradientType::RADIAL) {
238 SetRadialGradient(viewPort, gradient.value());
239 }
240 }
241
GradientHasColors()242 bool SvgGraphic::GradientHasColors()
243 {
244 auto& gradient = attributes_.fillState.GetGradient();
245 CHECK_NULL_RETURN(gradient, false);
246 auto gradientColors = gradient->GetColors();
247 if (gradientColors.empty()) {
248 LOGW("SvgGraphic::GradientHasColors gradient doesn't has color");
249 return false ;
250 }
251 return true;
252 }
253
InitBrush(RSCanvas & canvas,RSBrush & brush,const SvgCoordinateSystemContext & svgCoordinateSystemContext,PaintType type)254 bool SvgGraphic::InitBrush(RSCanvas& canvas, RSBrush& brush,
255 const SvgCoordinateSystemContext& svgCoordinateSystemContext, PaintType type)
256 {
257 bool setBrushResult = true;
258 switch (type) {
259 case PaintType::COLOR:
260 SetBrushColor(brush, svgCoordinateSystemContext.UseFillColor());
261 break;
262 case PaintType::LINEAR_GRADIENT:
263 setBrushResult = SetBrushLinearGradient(brush, svgCoordinateSystemContext);
264 break;
265 case PaintType::RADIAL_GRADIENT:
266 setBrushResult = SetBrushRadialGradient(brush, svgCoordinateSystemContext);
267 break;
268 case PaintType::PATTERN:
269 setBrushResult = SetBrushPattern(canvas, brush, svgCoordinateSystemContext);
270 break;
271 default:
272 break;
273 }
274 return setBrushResult;
275 }
276
277 // subgraph does not use image components parameter fillColor, example: mask
SetBrushColor(RSBrush & brush,bool useFillColor)278 void SvgGraphic::SetBrushColor(RSBrush& brush, bool useFillColor)
279 {
280 auto curOpacity = GetFillOpacity();
281 auto imageComponentColor = GetFillColor();
282 if (!imageComponentColor.has_value() || attributes_.fillState.IsFillNone() || !useFillColor) {
283 brush.SetColor(attributes_.fillState.GetColor().BlendOpacity(curOpacity).GetValue());
284 return;
285 }
286 brush.SetColor(imageComponentColor->BlendOpacity(curOpacity).GetValue());
287 }
288
ConvertToRsLinearGradient(const SvgLinearGradientInfo & linearGradientInfo)289 RsLinearGradient SvgGraphic::ConvertToRsLinearGradient(const SvgLinearGradientInfo& linearGradientInfo)
290 {
291 std::vector<RSScalar> pos;
292 std::vector<RSColorQuad> colors;
293 for (const auto& gradientColor : linearGradientInfo.colors) {
294 pos.push_back(static_cast<RSScalar>(gradientColor.GetDimension().Value()));
295 colors.push_back(
296 gradientColor.GetColor().BlendOpacity(gradientColor.GetOpacity()).GetValue());
297 }
298 RSPoint startPoint(static_cast<RSScalar>(linearGradientInfo.x1), static_cast<RSScalar>(linearGradientInfo.y1));
299 RSPoint endPoint(static_cast<RSScalar>(linearGradientInfo.x2), static_cast<RSScalar>(linearGradientInfo.y2));
300 return RsLinearGradient({ .startPoint_ = startPoint, .endPoint_ = endPoint,
301 .spreadMethod_ = static_cast<RSTileMode>(linearGradientInfo.spreadMethod),
302 .pos_ = pos, .colors_ = colors });
303 }
304
UpdateStrokeGradient(const Size & viewPort)305 void SvgGraphic::UpdateStrokeGradient(const Size& viewPort)
306 {
307 auto& gradient = attributes_.strokeState.GetGradient();
308 CHECK_NULL_VOID(gradient);
309 if (gradient->GetType() == OHOS::Ace::GradientType::LINEAR) {
310 SetLinearGradient(viewPort, gradient.value());
311 } else if (gradient->GetType() == OHOS::Ace::GradientType::RADIAL) {
312 SetRadialGradient(viewPort, gradient.value());
313 }
314 }
315
UpdateFillStyle(const std::optional<Color> & color,bool antiAlias)316 bool SvgGraphic::UpdateFillStyle(const std::optional<Color>& color, bool antiAlias)
317 {
318 if (!color && fillState_.GetColor() == Color::TRANSPARENT && !fillState_.GetGradient()) {
319 return false;
320 }
321 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
322 if (!fillState_.GetHref().empty() && CheckHrefPattern()) {
323 fillState_.SetColor(Color::TRANSPARENT);
324 }
325 }
326 double curOpacity = fillState_.GetOpacity().GetValue() * opacity_ * (1.0f / UINT8_MAX);
327 fillBrush_.SetAntiAlias(antiAlias);
328 if (fillState_.GetGradient()) {
329 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
330 SetGradientStyle(curOpacity);
331 return true;
332 }
333 return SetGradientStyle(curOpacity);
334 } else {
335 Color fillColor;
336 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
337 fillColor = (color) ? *color : fillState_.GetColor();
338 } else {
339 fillColor = (color && !fillState_.IsFillNone()) ? *color : fillState_.GetColor();
340 }
341 if (fillColor.GetColorSpace() == ColorSpace::DISPLAY_P3) {
342 auto p3Color = fillColor.BlendOpacity(curOpacity);
343 fillBrush_.SetColor({ p3Color.GetRed() / 255.0, p3Color.GetGreen() / 255.0, p3Color.GetBlue() / 255.0,
344 p3Color.GetAlpha() / 255.0 },
345 RSColorSpace::CreateRGB(RSCMSTransferFuncType::SRGB, RSCMSMatrixType::DCIP3));
346 } else {
347 fillBrush_.SetColor(fillColor.BlendOpacity(curOpacity).GetValue());
348 }
349 }
350 return true;
351 }
352
SetGradientFillStyle(const std::optional<OHOS::Ace::Gradient> & gradient,std::vector<RSScalar> pos,std::vector<RSColorQuad> colors)353 void SvgGraphic::SetGradientFillStyle(const std::optional<OHOS::Ace::Gradient>& gradient,
354 std::vector<RSScalar> pos, std::vector<RSColorQuad> colors)
355 {
356 RSMatrix result;
357 auto info = gradient->GetRadialGradientInfo();
358 auto center = RSPoint(static_cast<RSScalar>(info.cx), static_cast<RSScalar>(info.cy));
359 auto focal = RSPoint(static_cast<RSScalar>(info.fx), static_cast<RSScalar>(info.fy));
360 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
361 auto bounds = path_->GetBounds();
362 auto maxBounds = std::max(bounds.GetWidth(), bounds.GetHeight());
363 if (maxBounds != 0) {
364 RSMatrix m;
365 RSMatrix t;
366 auto scaleX = bounds.GetWidth() / maxBounds;
367 auto scaleY = bounds.GetHeight() / maxBounds;
368 auto transX = (1 - scaleX) * (bounds.GetLeft() + bounds.GetWidth() * HALF);
369 auto transY = (1 - scaleY) * (bounds.GetTop() + bounds.GetHeight() * HALF);
370 m.SetScale(scaleX, scaleY);
371 t.Translate(transX, transY);
372 t.PreConcat(m);
373 result = t;
374 }
375 if (center == focal) {
376 fillBrush_.SetShaderEffect(RSRecordingShaderEffect::CreateRadialGradient(center,
377 static_cast<RSScalar>(info.r), colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())));
378 } else {
379 fillBrush_.SetShaderEffect(RSRecordingShaderEffect::CreateTwoPointConical(focal, 0, center,
380 static_cast<RSScalar>(info.r), colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod()),
381 &result));
382 }
383 } else {
384 if (center == focal) {
385 fillBrush_.SetShaderEffect(RSRecordingShaderEffect::CreateRadialGradient(center,
386 static_cast<RSScalar>(info.r), colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())));
387 } else {
388 RSMatrix matrix;
389 fillBrush_.SetShaderEffect(RSRecordingShaderEffect::CreateTwoPointConical(focal, 0, center,
390 static_cast<RSScalar>(info.r), colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod()),
391 &matrix));
392 }
393 }
394 }
395
GetLocalMatrix(SvgLengthScaleUnit gradientUnits,const SvgCoordinateSystemContext & svgCoordinateSystemContext)396 RSMatrix SvgGraphic::GetLocalMatrix(SvgLengthScaleUnit gradientUnits,
397 const SvgCoordinateSystemContext& svgCoordinateSystemContext)
398 {
399 if (gradientUnits == SvgLengthScaleUnit::OBJECT_BOUNDING_BOX) {
400 auto bounds = svgCoordinateSystemContext.GetContainerRect();
401 RSMatrix m;
402 RSMatrix t;
403 m.SetScale(bounds.Width(), bounds.Height());
404 t.Translate(bounds.Left(), bounds.Top());
405 t.PreConcat(m);
406 return t;
407 }
408 return RSMatrix();
409 }
410
SetBrushLinearGradient(RSBrush & brush,const SvgCoordinateSystemContext & svgCoordinateSystemContext)411 bool SvgGraphic::SetBrushLinearGradient(RSBrush& brush, const SvgCoordinateSystemContext& svgCoordinateSystemContext)
412 {
413 if (!GradientHasColors()) {
414 return false;
415 }
416 auto svgContext = svgContext_.Upgrade();
417 CHECK_NULL_RETURN(svgContext, false);
418 auto linearGradientNode =
419 DynamicCast<SvgLinearGradient>(svgContext->GetSvgNodeById(attributes_.fillState.GetHref()));
420 CHECK_NULL_RETURN(linearGradientNode, false);
421 SetBrushOpacity(brush);
422 RsLinearGradient rsLinearGradient =
423 ConvertToRsLinearGradient(linearGradientNode->GetLinearGradientInfo(svgCoordinateSystemContext));
424 auto rsMatrix = rsLinearGradient.matrix_.value_or(RSMatrix());
425 RSMatrix t = GetLocalMatrix(linearGradientNode->GradientUnits(), svgCoordinateSystemContext);
426 rsMatrix = rsMatrix * t;
427 brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(rsLinearGradient.startPoint_,
428 rsLinearGradient.endPoint_, rsLinearGradient.colors_, rsLinearGradient.pos_,
429 rsLinearGradient.spreadMethod_, &rsMatrix));
430 return true;
431 }
432
ConvertToRsRadialGradient(const SvgRadialGradientInfo & radialGradientInfo)433 RsRadialGradient SvgGraphic::ConvertToRsRadialGradient(const SvgRadialGradientInfo& radialGradientInfo)
434 {
435 std::vector<RSScalar> pos;
436 std::vector<RSColorQuad> colors;
437 for (const auto& gradientColor : radialGradientInfo.colors) {
438 pos.push_back(static_cast<RSScalar>(gradientColor.GetDimension().Value()));
439 colors.push_back(
440 gradientColor.GetColor().BlendOpacity(gradientColor.GetOpacity()).GetValue());
441 }
442 RSPoint center(static_cast<RSScalar>(radialGradientInfo.cx), static_cast<RSScalar>(radialGradientInfo.cy));
443 RSPoint focal(static_cast<RSScalar>(radialGradientInfo.fx), static_cast<RSScalar>(radialGradientInfo.fy));
444
445 return RsRadialGradient({ .center_ = center, .focal_ = focal,
446 .spreadMethod_ = static_cast<RSTileMode>(radialGradientInfo.spreadMethod),
447 .r_ = static_cast<RSScalar>(radialGradientInfo.r), .pos_ = pos, .colors_ = colors});
448 }
449
SetBrushRadialGradient(RSBrush & brush,const SvgCoordinateSystemContext & svgCoordinateSystemContext)450 bool SvgGraphic::SetBrushRadialGradient(RSBrush& brush, const SvgCoordinateSystemContext& svgCoordinateSystemContext)
451 {
452 if (!GradientHasColors()) {
453 return false;
454 }
455 auto svgContext = svgContext_.Upgrade();
456 CHECK_NULL_RETURN(svgContext, false);
457 auto radialGradientNode =
458 DynamicCast<SvgRadialGradient>(svgContext->GetSvgNodeById(attributes_.fillState.GetHref()));
459 CHECK_NULL_RETURN(radialGradientNode, false);
460 SetBrushOpacity(brush);
461 auto rsRadialGradient =
462 ConvertToRsRadialGradient(radialGradientNode->GetRadialGradientInfo(svgCoordinateSystemContext));
463 auto rsMatrix = rsRadialGradient.matrix_.value_or(RSMatrix());
464 RSMatrix t = GetLocalMatrix(radialGradientNode->GradientUnits(), svgCoordinateSystemContext);
465 rsMatrix = rsMatrix * t;
466 if (rsRadialGradient.center_ == rsRadialGradient.focal_) {
467 brush.SetShaderEffect(RSRecordingShaderEffect::CreateRadialGradient(rsRadialGradient.center_,
468 rsRadialGradient.r_, rsRadialGradient.colors_, rsRadialGradient.pos_, rsRadialGradient.spreadMethod_,
469 &rsMatrix));
470 } else {
471 brush.SetShaderEffect(RSRecordingShaderEffect::CreateTwoPointConical(rsRadialGradient.focal_, 0,
472 rsRadialGradient.center_, rsRadialGradient.r_, rsRadialGradient.colors_,
473 rsRadialGradient.pos_, rsRadialGradient.spreadMethod_, &rsMatrix));
474 }
475 return true;
476 }
477
SetBrushPattern(RSCanvas & canvas,RSBrush & brush,const SvgCoordinateSystemContext & svgCoordinateSystemContext)478 bool SvgGraphic::SetBrushPattern(RSCanvas& canvas, RSBrush& brush,
479 const SvgCoordinateSystemContext& svgCoordinateSystemContext)
480 {
481 auto svgContext = svgContext_.Upgrade();
482 CHECK_NULL_RETURN(svgContext, false);
483 auto refPatternNode = DynamicCast<SvgPattern>(svgContext->GetSvgNodeById(attributes_.fillState.GetHref()));
484 CHECK_NULL_RETURN(refPatternNode, false);
485 refPatternNode->OnPatternEffect(canvas, brush, svgCoordinateSystemContext);
486 return true;
487 }
488
GetFillOpacity()489 double SvgGraphic::GetFillOpacity()
490 {
491 auto curOpacity = 1.0;
492 if (attributes_.hasOpacity) {
493 curOpacity = opacity_ * (1.0f / UINT8_MAX);
494 }
495 curOpacity *= attributes_.fillState.GetOpacity().GetValue();
496 return curOpacity;
497 }
498
GetStrokeOpacity()499 double SvgGraphic::GetStrokeOpacity()
500 {
501 auto curOpacity = 1.0;
502 if (attributes_.hasOpacity) {
503 curOpacity = opacity_ * (1.0f / UINT8_MAX);
504 }
505 curOpacity *= attributes_.strokeState.GetOpacity().GetValue();
506 return curOpacity;
507 }
508
SetBrushOpacity(RSBrush & brush)509 void SvgGraphic::SetBrushOpacity(RSBrush& brush)
510 {
511 uint32_t alpha = GetFillOpacity() * UINT8_MAX;
512 brush.SetAlpha(alpha);
513 return;
514 }
515
SetPenOpacity(RSPen & pen)516 void SvgGraphic::SetPenOpacity(RSPen& pen)
517 {
518 uint32_t alpha = GetStrokeOpacity() * UINT8_MAX;
519 pen.SetAlpha(alpha);
520 return;
521 }
522
SetGradientStyle(double opacity)523 bool SvgGraphic::SetGradientStyle(double opacity)
524 {
525 auto gradient = fillState_.GetGradient();
526 CHECK_NULL_RETURN(gradient, false);
527 auto gradientColors = gradient->GetColors();
528 if (gradientColors.empty()) {
529 return false;
530 }
531 std::vector<RSScalar> pos;
532 std::vector<RSColorQuad> colors;
533 for (const auto& gradientColor : gradientColors) {
534 pos.push_back(static_cast<RSScalar>(gradientColor.GetDimension().Value()));
535 colors.push_back(
536 gradientColor.GetColor().BlendOpacity(gradientColor.GetOpacity()).BlendOpacity(opacity).GetValue());
537 }
538 if (gradient->GetType() == OHOS::Ace::GradientType::LINEAR) {
539 auto info = gradient->GetLinearGradientInfo();
540 std::array<RSPoint, 2> pts = { RSPoint(static_cast<RSScalar>(info.x1), static_cast<RSScalar>(info.y1)),
541 RSPoint(static_cast<RSScalar>(info.x2), static_cast<RSScalar>(info.y2)) };
542 fillBrush_.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
543 pts[0], pts[1], colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())));
544 }
545 if (gradient->GetType() == OHOS::Ace::GradientType::RADIAL) {
546 SetGradientFillStyle(gradient, pos, colors);
547 }
548 return true;
549 }
550
SetStrokeGradientStyle(double opacity)551 void SvgGraphic::SetStrokeGradientStyle(double opacity)
552 {
553 const auto& strokeState = attributes_.strokeState;
554 auto gradient = strokeState.GetGradient();
555 CHECK_NULL_VOID(gradient);
556 auto gradientColors = gradient->GetColors();
557 if (gradientColors.empty()) {
558 return;
559 }
560 std::vector<RSScalar> pos;
561 std::vector<RSColorQuad> colors;
562 for (const auto& gradientColor : gradientColors) {
563 pos.push_back(static_cast<RSScalar>(gradientColor.GetDimension().Value()));
564 colors.push_back(
565 gradientColor.GetColor().BlendOpacity(gradientColor.GetOpacity()).BlendOpacity(opacity).GetValue());
566 }
567 if (gradient->GetType() == OHOS::Ace::GradientType::LINEAR) {
568 auto info = gradient->GetLinearGradientInfo();
569 std::array<RSPoint, 2> pts = { RSPoint(static_cast<RSScalar>(info.x1), static_cast<RSScalar>(info.y1)),
570 RSPoint(static_cast<RSScalar>(info.x2), static_cast<RSScalar>(info.y2)) };
571 strokePen_.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
572 pts[0], pts[1], colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())));
573 }
574 if (gradient->GetType() == OHOS::Ace::GradientType::RADIAL) {
575 auto info = gradient->GetRadialGradientInfo();
576 auto center = RSPoint(static_cast<RSScalar>(info.cx), static_cast<RSScalar>(info.cy));
577 auto focal = RSPoint(static_cast<RSScalar>(info.fx), static_cast<RSScalar>(info.fx));
578 if (center == focal) {
579 strokePen_.SetShaderEffect(RSRecordingShaderEffect::CreateRadialGradient(center,
580 static_cast<RSScalar>(info.r), colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod())));
581 } else {
582 RSMatrix matrix;
583 strokePen_.SetShaderEffect(RSRecordingShaderEffect::CreateTwoPointConical(focal, 0, center,
584 static_cast<RSScalar>(info.r), colors, pos, static_cast<RSTileMode>(gradient->GetSpreadMethod()),
585 &matrix));
586 }
587 }
588 }
589
GetStrokeType()590 PaintType SvgGraphic::GetStrokeType()
591 {
592 if (attributes_.strokeState.GetColor() == Color::TRANSPARENT) {
593 return PaintType::NONE;
594 }
595 if (attributes_.strokeState.HasColor()) {
596 return PaintType::COLOR;
597 }
598 if (!attributes_.strokeState.GetHref().empty()) {
599 return GetHrefType(attributes_.strokeState.GetHref());
600 }
601 auto& gradient = attributes_.strokeState.GetGradient();
602 if (gradient.has_value()) {
603 auto href = gradient->GetHref();
604 if (!href.empty()) {
605 attributes_.strokeState.SetHref(href);
606 return GetHrefType(attributes_.strokeState.GetHref());
607 }
608 }
609 return PaintType::COLOR;
610 }
611
InitPenFill(RSPen & rsPen,const SvgCoordinateSystemContext & svgCoordinateSystemContext,PaintType type)612 bool SvgGraphic::InitPenFill(RSPen& rsPen, const SvgCoordinateSystemContext& svgCoordinateSystemContext,
613 PaintType type)
614 {
615 bool setPenResult = true;
616 switch (type) {
617 case PaintType::COLOR:
618 SetPenColor(rsPen);
619 break;
620 case PaintType::LINEAR_GRADIENT:
621 setPenResult = SetPenLinearGradient(rsPen, svgCoordinateSystemContext);
622 break;
623 case PaintType::RADIAL_GRADIENT:
624 setPenResult = SetPenRadialGradient(rsPen, svgCoordinateSystemContext);
625 break;
626 case PaintType::PATTERN:
627 break;
628 default:
629 break;
630 }
631 return setPenResult;
632 }
633
SetPenStyle(RSPen & rsPen)634 void SvgGraphic::SetPenStyle(RSPen& rsPen)
635 {
636 if (attributes_.strokeState.GetLineCap() == LineCapStyle::ROUND) {
637 rsPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
638 } else if (attributes_.strokeState.GetLineCap() == LineCapStyle::SQUARE) {
639 rsPen.SetCapStyle(RSPen::CapStyle::SQUARE_CAP);
640 } else {
641 rsPen.SetCapStyle(RSPen::CapStyle::FLAT_CAP);
642 }
643 if (attributes_.strokeState.GetLineJoin() == LineJoinStyle::ROUND) {
644 rsPen.SetJoinStyle(RSPen::JoinStyle::ROUND_JOIN);
645 } else if (attributes_.strokeState.GetLineJoin() == LineJoinStyle::BEVEL) {
646 rsPen.SetJoinStyle(RSPen::JoinStyle::BEVEL_JOIN);
647 } else {
648 rsPen.SetJoinStyle(RSPen::JoinStyle::MITER_JOIN);
649 }
650 rsPen.SetWidth(static_cast<RSScalar>(attributes_.strokeState.GetLineWidth().Value()));
651 rsPen.SetMiterLimit(static_cast<RSScalar>(attributes_.strokeState.GetMiterLimit()));
652 rsPen.SetAntiAlias(true);
653 auto lineDashState = attributes_.strokeState.GetLineDash().lineDash;
654 if (lineDashState.empty()) {
655 return;
656 }
657
658 auto intervalsLen = lineDashState.size();
659 if (lineDashState.size() % 2 != 0) { // 2:judging odd
660 intervalsLen = lineDashState.size() * 2; // 2:double size
661 }
662 RSScalar intervals[intervalsLen];
663 for (size_t i = 0; i < intervalsLen; ++i) {
664 intervals[i] = static_cast<RSScalar>(lineDashState[i % lineDashState.size()]);
665 }
666 RSScalar phase = static_cast<RSScalar>(attributes_.strokeState.GetLineDash().dashOffset);
667 rsPen.SetPathEffect(RSRecordingPathEffect::CreateDashPathEffect(intervals, intervalsLen, phase));
668 }
669
UpdateStrokeStyle(bool antiAlias)670 bool SvgGraphic::UpdateStrokeStyle(bool antiAlias)
671 {
672 const auto& strokeState = attributes_.strokeState;
673 auto colorFilter = GetColorFilter();
674 if (!colorFilter.has_value() && strokeState.GetColor() == Color::TRANSPARENT && !strokeState.GetGradient()) {
675 return false;
676 }
677 if (!GreatNotEqual(strokeState.GetLineWidth().Value(), 0.0)) {
678 return false;
679 }
680 double curOpacity = strokeState.GetOpacity().GetValue() * opacity_ * (1.0f / UINT8_MAX);
681 if (strokeState.GetGradient()) {
682 SetStrokeGradientStyle(curOpacity);
683 } else {
684 strokePen_.SetColor(strokeState.GetColor().BlendOpacity(curOpacity).GetValue());
685 }
686 if (strokeState.GetLineCap() == LineCapStyle::ROUND) {
687 strokePen_.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
688 } else if (strokeState.GetLineCap() == LineCapStyle::SQUARE) {
689 strokePen_.SetCapStyle(RSPen::CapStyle::SQUARE_CAP);
690 } else {
691 strokePen_.SetCapStyle(RSPen::CapStyle::FLAT_CAP);
692 }
693 if (strokeState.GetLineJoin() == LineJoinStyle::ROUND) {
694 strokePen_.SetJoinStyle(RSPen::JoinStyle::ROUND_JOIN);
695 } else if (strokeState.GetLineJoin() == LineJoinStyle::BEVEL) {
696 strokePen_.SetJoinStyle(RSPen::JoinStyle::BEVEL_JOIN);
697 } else {
698 strokePen_.SetJoinStyle(RSPen::JoinStyle::MITER_JOIN);
699 }
700 strokePen_.SetWidth(static_cast<RSScalar>(strokeState.GetLineWidth().Value()));
701 strokePen_.SetMiterLimit(static_cast<RSScalar>(strokeState.GetMiterLimit()));
702 strokePen_.SetAntiAlias(antiAlias);
703
704 auto filter = strokePen_.GetFilter();
705 UpdateColorFilter(filter);
706 strokePen_.SetFilter(filter);
707 UpdateLineDash();
708 return true;
709 }
710
UpdateLineDash()711 void SvgGraphic::UpdateLineDash()
712 {
713 const auto& strokeState = attributes_.strokeState;
714 if (!strokeState.GetLineDash().lineDash.empty()) {
715 auto lineDashState = strokeState.GetLineDash().lineDash;
716 if (!Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
717 RSScalar intervals[lineDashState.size()];
718 for (size_t i = 0; i < lineDashState.size(); ++i) {
719 intervals[i] = static_cast<RSScalar>(lineDashState[i]);
720 }
721 RSScalar phase = static_cast<RSScalar>(strokeState.GetLineDash().dashOffset);
722 strokePen_.SetPathEffect(
723 RSRecordingPathEffect::CreateDashPathEffect(intervals, lineDashState.size(), phase));
724 } else {
725 auto intervalsLen = lineDashState.size();
726
727 if (lineDashState.size() % 2 != 0) { // 2:judging odd
728 intervalsLen = lineDashState.size() * 2; // 2:double size
729 }
730 RSScalar intervals[intervalsLen];
731 for (size_t i = 0; i < intervalsLen; ++i) {
732 intervals[i] = static_cast<RSScalar>(lineDashState[i % lineDashState.size()]);
733 }
734 RSScalar phase = static_cast<RSScalar>(strokeState.GetLineDash().dashOffset);
735 strokePen_.SetPathEffect(RSRecordingPathEffect::CreateDashPathEffect(intervals, intervalsLen, phase));
736 }
737 }
738 }
739
SetPenColor(RSPen & rsPen)740 void SvgGraphic::SetPenColor(RSPen& rsPen)
741 {
742 auto curOpacity = GetStrokeOpacity();
743 rsPen.SetColor(attributes_.strokeState.GetColor().BlendOpacity(curOpacity).GetValue());
744 }
745
AddColorFilterEffect(RSPen & rsPen)746 void SvgGraphic::AddColorFilterEffect(RSPen& rsPen)
747 {
748 auto colorFilter = GetColorFilter();
749 if (!colorFilter.has_value()) {
750 return;
751 }
752 if (colorFilter.value().colorFilterMatrix_) {
753 RSColorMatrix colorMatrix;
754 colorMatrix.SetArray(colorFilter.value().colorFilterMatrix_->data());
755 auto filter = rsPen.GetFilter();
756 filter.SetColorFilter(RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix));
757 rsPen.SetFilter(filter);
758 return;
759 }
760 if (!colorFilter.value().colorFilterDrawing_) {
761 return;
762 }
763 auto colorFilterSptrAddr = static_cast<std::shared_ptr<RSColorFilter>*>(
764 colorFilter.value().colorFilterDrawing_->GetDrawingColorFilterSptrAddr());
765 if (!colorFilterSptrAddr || !(*colorFilterSptrAddr)) {
766 return;
767 }
768 auto filter = rsPen.GetFilter();
769 filter.SetColorFilter(*colorFilterSptrAddr);
770 rsPen.SetFilter(filter);
771 }
772
UpdateColorFilter(RSFilter & filter)773 void SvgGraphic::UpdateColorFilter(RSFilter& filter)
774 {
775 auto colorFilter = GetColorFilter();
776 if (!colorFilter.has_value()) {
777 return;
778 }
779 if (colorFilter.value().colorFilterMatrix_) {
780 RSColorMatrix colorMatrix;
781 colorMatrix.SetArray(colorFilter.value().colorFilterMatrix_->data());
782 filter.SetColorFilter(RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix));
783 return;
784 }
785 if (!colorFilter.value().colorFilterDrawing_) {
786 return;
787 }
788 auto colorFilterSptrAddr = static_cast<std::shared_ptr<RSColorFilter>*>(
789 colorFilter.value().colorFilterDrawing_->GetDrawingColorFilterSptrAddr());
790 if (!colorFilterSptrAddr || !(*colorFilterSptrAddr)) {
791 return;
792 }
793 filter.SetColorFilter(*colorFilterSptrAddr);
794 }
795
RectifyTargetSize(const Rect & bounds,double & width,double & height)796 void SvgGraphic::RectifyTargetSize(const Rect& bounds, double& width, double& height)
797 {
798 if (NearZero(bounds.Height())) {
799 return;
800 }
801 auto scalar = bounds.Width() / bounds.Height();
802 width = 2 * bounds.Height() * sin(std::atan(scalar)) * cos(atan(scalar)); // 2: algorithm parameters
803 height = 2 * bounds.Height() * sin(std::atan(scalar)) * sin(atan(scalar)); // 2: algorithm parameters
804 }
805
SetPenLinearGradient(RSPen & rsPen,const SvgCoordinateSystemContext & svgCoordinateSystemContext)806 bool SvgGraphic::SetPenLinearGradient(RSPen& rsPen, const SvgCoordinateSystemContext& svgCoordinateSystemContext)
807 {
808 if (!GradientHasColors()) {
809 return false;
810 }
811 auto svgContext = svgContext_.Upgrade();
812 CHECK_NULL_RETURN(svgContext, false);
813 auto linearGradientNode =
814 DynamicCast<SvgLinearGradient>(svgContext->GetSvgNodeById(attributes_.strokeState.GetHref()));
815 CHECK_NULL_RETURN(linearGradientNode, false);
816 SetPenOpacity(rsPen);
817 RsLinearGradient rsLinearGradient =
818 ConvertToRsLinearGradient(linearGradientNode->GetLinearGradientInfo(svgCoordinateSystemContext));
819 auto rsMatrix = rsLinearGradient.matrix_.value_or(RSMatrix());
820 RSMatrix t = GetLocalMatrix(linearGradientNode->GradientUnits(), svgCoordinateSystemContext);
821 rsMatrix = rsMatrix * t;
822 rsPen.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
823 rsLinearGradient.startPoint_, rsLinearGradient.endPoint_, rsLinearGradient.colors_,
824 rsLinearGradient.pos_, rsLinearGradient.spreadMethod_, &rsMatrix));
825 return true;
826 }
827
SetPenRadialGradient(RSPen & rsPen,const SvgCoordinateSystemContext & svgCoordinateSystemContext)828 bool SvgGraphic::SetPenRadialGradient(RSPen& rsPen, const SvgCoordinateSystemContext& svgCoordinateSystemContext)
829 {
830 if (!GradientHasColors()) {
831 return false;
832 }
833 auto svgContext = svgContext_.Upgrade();
834 CHECK_NULL_RETURN(svgContext, false);
835 auto radialGradientNode =
836 DynamicCast<SvgRadialGradient>(svgContext->GetSvgNodeById(attributes_.strokeState.GetHref()));
837 CHECK_NULL_RETURN(radialGradientNode, false);
838 SetPenOpacity(rsPen);
839 auto rsRadialGradient =
840 ConvertToRsRadialGradient(radialGradientNode->GetRadialGradientInfo(svgCoordinateSystemContext));
841 auto rsMatrix = rsRadialGradient.matrix_.value_or(RSMatrix());
842 RSMatrix t = GetLocalMatrix(radialGradientNode->GradientUnits(), svgCoordinateSystemContext);
843 rsMatrix = rsMatrix * t;
844 if (rsRadialGradient.center_ == rsRadialGradient.focal_) {
845 rsPen.SetShaderEffect(RSRecordingShaderEffect::CreateRadialGradient(rsRadialGradient.center_,
846 rsRadialGradient.r_, rsRadialGradient.colors_, rsRadialGradient.pos_, rsRadialGradient.spreadMethod_,
847 &rsMatrix));
848 } else {
849 rsPen.SetShaderEffect(RSRecordingShaderEffect::CreateTwoPointConical(rsRadialGradient.focal_, 0,
850 rsRadialGradient.center_, rsRadialGradient.r_, rsRadialGradient.colors_, rsRadialGradient.pos_,
851 rsRadialGradient.spreadMethod_, &rsMatrix));
852 }
853 return true;
854 }
855
GetFillColor()856 std::optional<Color> SvgGraphic::GetFillColor()
857 {
858 auto svgContext = svgContext_.Upgrade();
859 CHECK_NULL_RETURN(svgContext, std::nullopt);
860 return svgContext->GetFillColor();
861 }
862
ApplyTransform(RSRecordingPath & path)863 void SvgGraphic::ApplyTransform(RSRecordingPath& path)
864 {
865 auto matrix = RSMatrix();
866 if (attributes_.transformVec.size() == 1) {
867 if (attributes_.transformVec[0].funcType == "translate") {
868 auto ret = NGSvgTransform::CreateTranslate(attributes_.transformVec[0].paramVec, matrix);
869 if (ret) {
870 LOGD("SvgGraphic::ApplyTransform calling translate");
871 path.Transform(matrix);
872 }
873 }
874 return;
875 }
876 }
877 } // namespace OHOS::Ace::NG
878