• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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