• 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 "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