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 "frameworks/core/components_ng/svg/parse/svg_pattern.h"
17
18 #include "core/common/container.h"
19 #include "core/components_ng/svg/base/svg_length_scale_rule.h"
20 #include "frameworks/core/components_ng/svg/parse/svg_constants.h"
21 #include "core/components_ng/render/adapter/rosen_render_context.h"
22 #include "core/components_ng/render/drawing.h"
23
24 namespace OHOS::Ace::NG {
25
SvgPattern()26 SvgPattern::SvgPattern() : SvgQuote() {}
27
Create()28 RefPtr<SvgNode> SvgPattern::Create()
29 {
30 return AceType::MakeRefPtr<SvgPattern>();
31 }
32
OnDrawTraversedBefore(RSCanvas & canvas,const Size & viewPort,const std::optional<Color> & color)33 void SvgPattern::OnDrawTraversedBefore(RSCanvas& canvas, const Size& viewPort, const std::optional<Color>& color)
34 {
35 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) {
36 auto scaleX = viewPort.Width() / patternAttr_.width.ConvertToPx();
37 auto scaleY = viewPort.Height() / patternAttr_.height.ConvertToPx();
38 canvas.Save();
39 canvas.Scale(scaleX, scaleY);
40 return;
41 }
42 canvas.Save();
43 auto actualWdith = boundingBoxRect_.Width() * patternAttr_.width.Value();
44 auto actualHeight = boundingBoxRect_.Height() * patternAttr_.height.Value();
45 auto actualX = boundingBoxRect_.Width() * patternAttr_.x.Value();
46 auto actualY = boundingBoxRect_.Height() * patternAttr_.y.Value();
47 RSRect clipRect(actualX, actualY, actualX + actualWdith, actualY + actualHeight);
48 canvas.ClipRect(clipRect, RSClipOp::INTERSECT, true);
49
50 if (patternAttr_.patternContentUnits != SvgLengthScaleUnit::USER_SPACE_ON_USE) {
51 auto scaleX = static_cast<float>(boundingBoxRect_.Width() / patternAttr_.width.Value());
52 auto scaleY = static_cast<float>(boundingBoxRect_.Height() / patternAttr_.height.Value());
53 canvas.Scale(scaleX, scaleY);
54 }
55 }
56
OnDrawTraversedAfter(RSCanvas & canvas,const Size & viewPort,const std::optional<Color> & color)57 void SvgPattern::OnDrawTraversedAfter(RSCanvas& canvas, const Size& viewPort, const std::optional<Color>& color)
58 {
59 canvas.Restore();
60 }
61
OnPatternEffect(RSCanvas & canvas,RSBrush & brush,const SvgCoordinateSystemContext & svgCoordinateSystemContext)62 void SvgPattern::OnPatternEffect(RSCanvas& canvas, RSBrush& brush,
63 const SvgCoordinateSystemContext& svgCoordinateSystemContext)
64 {
65 canvas.Save();
66 auto patternRule = svgCoordinateSystemContext.BuildScaleRule(patternAttr_.patternUnits);
67 auto measureX = GetRegionPosition(patternAttr_.x, patternRule, SvgLengthType::HORIZONTAL);
68 auto measureY = GetRegionPosition(patternAttr_.y, patternRule, SvgLengthType::VERTICAL);
69 auto measuredWidth = GetRegionLength(patternAttr_.width, patternRule, SvgLengthType::HORIZONTAL);
70 auto measuredHeight = GetRegionLength(patternAttr_.height, patternRule, SvgLengthType::VERTICAL);
71 RSRect tileRect(0, 0, measuredWidth, measuredHeight);
72 auto pictureRecorder = std::make_unique<RSPictureRecorder>();
73 auto patternCanvas = pictureRecorder->BeginRecording(measuredWidth, measuredHeight);
74 auto patternContentRule = BuildContentScaleRule(svgCoordinateSystemContext, patternAttr_.patternContentUnits);
75 auto containerSize = svgCoordinateSystemContext.GetContainerRect().GetSize();
76 TransformForCurrentOBB(*patternCanvas, patternContentRule, containerSize, Offset(0.0, 0.0));
77 for (auto& child : children_) {
78 auto node = DynamicCast<SvgNode>(child);
79 if (node) {
80 node->Draw(*patternCanvas, patternContentRule);
81 }
82 }
83 RSMatrix patternMatrix;
84 RSMatrix localMatrix;
85 localMatrix.Translate(measureX, measureY);
86 patternMatrix.PreConcat(localMatrix);
87 auto picture = pictureRecorder->FinishRecordingAsPicture();
88 auto shader = RSShaderEffect::CreatePictureShader(*picture, RSTileMode::REPEAT, RSTileMode::REPEAT,
89 RSFilterMode::LINEAR, patternMatrix, tileRect);
90 brush.SetShaderEffect(shader);
91 canvas.Restore();
92 }
93
ParseAndSetSpecializedAttr(const std::string & name,const std::string & value)94 bool SvgPattern::ParseAndSetSpecializedAttr(const std::string& name, const std::string& value)
95 {
96 static const LinearMapNode<void (*)(const std::string&, SvgPatternAttribute&)> attrs[] = {
97 { SVG_HEIGHT,
98 [](const std::string& val, SvgPatternAttribute& attr) {
99 attr.height = SvgAttributesParser::ParseDimension(val);
100 } },
101 { SVG_PATTERN_CONTENT_UNITS,
102 [](const std::string& val, SvgPatternAttribute& attr) {
103 attr.patternContentUnits = (val == "objectBoundingBox") ? SvgLengthScaleUnit::OBJECT_BOUNDING_BOX :
104 SvgLengthScaleUnit::USER_SPACE_ON_USE;
105 } },
106 { SVG_PATTERN_UNITS,
107 [](const std::string& val, SvgPatternAttribute& attr) {
108 attr.patternUnits = (val == "userSpaceOnUse") ? SvgLengthScaleUnit::USER_SPACE_ON_USE :
109 SvgLengthScaleUnit::OBJECT_BOUNDING_BOX;
110 } },
111 { SVG_VIEW_BOX,
112 [](const std::string& val, SvgPatternAttribute& attr) {
113 if (val.empty()) {
114 return;
115 }
116 std::vector<double> viewBox;
117 StringUtils::StringSplitter(val, ' ', viewBox);
118 if (viewBox.size() == 4) {
119 attr.viewBox = Rect(viewBox[0], viewBox[1], viewBox[2], viewBox[3]);
120 }
121 } },
122 { SVG_WIDTH,
123 [](const std::string& val, SvgPatternAttribute& attr) {
124 attr.width = SvgAttributesParser::ParseDimension(val);
125 } },
126 { SVG_X,
127 [](const std::string& val, SvgPatternAttribute& attr) {
128 attr.x = SvgAttributesParser::ParseDimension(val);
129 } },
130 { SVG_Y,
131 [](const std::string& val, SvgPatternAttribute& attr) {
132 attr.y = SvgAttributesParser::ParseDimension(val);
133 } },
134 };
135
136 std::string key = name;
137 StringUtils::TransformStrCase(key, StringUtils::TEXT_CASE_LOWERCASE);
138 auto attrIter = BinarySearchFindIndex(attrs, ArraySize(attrs), key.c_str());
139 if (attrIter != -1) {
140 attrs[attrIter].value(value, patternAttr_);
141 return true;
142 }
143 return false;
144 }
145
146 } // namespace OHOS::Ace::NG
147