Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/dom/SVGTextContentElement.h"
8 :
9 : #include "mozilla/dom/SVGIRect.h"
10 : #include "nsBidiUtils.h"
11 : #include "nsISVGPoint.h"
12 : #include "nsTextFragment.h"
13 : #include "nsTextFrameUtils.h"
14 : #include "nsTextNode.h"
15 : #include "SVGTextFrame.h"
16 :
17 : namespace mozilla {
18 : namespace dom {
19 :
20 : nsSVGEnumMapping SVGTextContentElement::sLengthAdjustMap[] = {
21 : { &nsGkAtoms::spacing, SVG_LENGTHADJUST_SPACING },
22 : { &nsGkAtoms::spacingAndGlyphs, SVG_LENGTHADJUST_SPACINGANDGLYPHS },
23 : { nullptr, 0 }
24 : };
25 :
26 : nsSVGElement::EnumInfo SVGTextContentElement::sEnumInfo[1] =
27 : {
28 : { &nsGkAtoms::lengthAdjust, sLengthAdjustMap, SVG_LENGTHADJUST_SPACING }
29 : };
30 :
31 : nsSVGElement::LengthInfo SVGTextContentElement::sLengthInfo[1] =
32 : {
33 : { &nsGkAtoms::textLength, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::XY }
34 : };
35 :
36 : SVGTextFrame*
37 0 : SVGTextContentElement::GetSVGTextFrame()
38 : {
39 0 : nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
40 : nsIFrame* textFrame =
41 0 : nsLayoutUtils::GetClosestFrameOfType(frame, LayoutFrameType::SVGText);
42 0 : return static_cast<SVGTextFrame*>(textFrame);
43 : }
44 :
45 : SVGTextFrame*
46 0 : SVGTextContentElement::GetSVGTextFrameForNonLayoutDependentQuery()
47 : {
48 0 : nsIFrame* frame = GetPrimaryFrame(FlushType::Frames);
49 : nsIFrame* textFrame =
50 0 : nsLayoutUtils::GetClosestFrameOfType(frame, LayoutFrameType::SVGText);
51 0 : return static_cast<SVGTextFrame*>(textFrame);
52 : }
53 :
54 : already_AddRefed<SVGAnimatedLength>
55 0 : SVGTextContentElement::TextLength()
56 : {
57 0 : return LengthAttributes()[TEXTLENGTH].ToDOMAnimatedLength(this);
58 : }
59 :
60 : already_AddRefed<SVGAnimatedEnumeration>
61 0 : SVGTextContentElement::LengthAdjust()
62 : {
63 0 : return EnumAttributes()[LENGTHADJUST].ToDOMAnimatedEnum(this);
64 : }
65 :
66 : //----------------------------------------------------------------------
67 :
68 : template<typename T>
69 : static bool
70 0 : FragmentHasSkippableCharacter(const T* aBuffer, uint32_t aLength)
71 : {
72 0 : for (uint32_t i = 0; i < aLength; i++) {
73 0 : if (nsTextFrameUtils::IsSkippableCharacterForTransformText(aBuffer[i])) {
74 0 : return true;
75 : }
76 : }
77 0 : return false;
78 : }
79 :
80 : Maybe<int32_t>
81 0 : SVGTextContentElement::GetNonLayoutDependentNumberOfChars()
82 : {
83 0 : SVGTextFrame* frame = GetSVGTextFrameForNonLayoutDependentQuery();
84 0 : if (!frame || frame != GetPrimaryFrame()) {
85 : // Only support this fast path on <text>, not child <tspan>s, etc.
86 0 : return Some(0);
87 : }
88 :
89 0 : uint32_t num = 0;
90 :
91 0 : for (nsINode* n = Element::GetFirstChild(); n; n = n->GetNextSibling()) {
92 0 : if (!n->IsNodeOfType(nsINode::eTEXT)) {
93 0 : return Nothing();
94 : }
95 :
96 0 : const nsTextFragment* text = static_cast<nsTextNode*>(n)->GetText();
97 0 : uint32_t length = text->GetLength();
98 :
99 0 : if (text->Is2b()) {
100 0 : if (FragmentHasSkippableCharacter(text->Get2b(), length)) {
101 0 : return Nothing();
102 : }
103 : } else {
104 0 : auto buffer = reinterpret_cast<const uint8_t*>(text->Get1b());
105 0 : if (FragmentHasSkippableCharacter(buffer, length)) {
106 0 : return Nothing();
107 : }
108 : }
109 :
110 0 : num += length;
111 : }
112 :
113 0 : return Some(num);
114 : }
115 :
116 : int32_t
117 0 : SVGTextContentElement::GetNumberOfChars()
118 : {
119 0 : Maybe<int32_t> num = GetNonLayoutDependentNumberOfChars();
120 0 : if (num) {
121 0 : return *num;
122 : }
123 :
124 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
125 0 : return textFrame ? textFrame->GetNumberOfChars(this) : 0;
126 : }
127 :
128 : float
129 0 : SVGTextContentElement::GetComputedTextLength()
130 : {
131 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
132 0 : return textFrame ? textFrame->GetComputedTextLength(this) : 0.0f;
133 : }
134 :
135 : void
136 0 : SVGTextContentElement::SelectSubString(uint32_t charnum, uint32_t nchars, ErrorResult& rv)
137 : {
138 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
139 0 : if (!textFrame)
140 0 : return;
141 :
142 0 : rv = textFrame->SelectSubString(this, charnum, nchars);
143 : }
144 :
145 : float
146 0 : SVGTextContentElement::GetSubStringLength(uint32_t charnum, uint32_t nchars, ErrorResult& rv)
147 : {
148 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
149 0 : if (!textFrame)
150 0 : return 0.0f;
151 :
152 0 : float length = 0.0f;
153 0 : rv = textFrame->GetSubStringLength(this, charnum, nchars, &length);
154 0 : return length;
155 : }
156 :
157 : already_AddRefed<nsISVGPoint>
158 0 : SVGTextContentElement::GetStartPositionOfChar(uint32_t charnum, ErrorResult& rv)
159 : {
160 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
161 0 : if (!textFrame) {
162 0 : rv.Throw(NS_ERROR_FAILURE);
163 0 : return nullptr;
164 : }
165 :
166 0 : nsCOMPtr<nsISVGPoint> point;
167 0 : rv = textFrame->GetStartPositionOfChar(this, charnum, getter_AddRefs(point));
168 0 : return point.forget();
169 : }
170 :
171 : already_AddRefed<nsISVGPoint>
172 0 : SVGTextContentElement::GetEndPositionOfChar(uint32_t charnum, ErrorResult& rv)
173 : {
174 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
175 0 : if (!textFrame) {
176 0 : rv.Throw(NS_ERROR_FAILURE);
177 0 : return nullptr;
178 : }
179 :
180 0 : nsCOMPtr<nsISVGPoint> point;
181 0 : rv = textFrame->GetEndPositionOfChar(this, charnum, getter_AddRefs(point));
182 0 : return point.forget();
183 : }
184 :
185 : already_AddRefed<SVGIRect>
186 0 : SVGTextContentElement::GetExtentOfChar(uint32_t charnum, ErrorResult& rv)
187 : {
188 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
189 :
190 0 : if (!textFrame) {
191 0 : rv.Throw(NS_ERROR_FAILURE);
192 0 : return nullptr;
193 : }
194 :
195 0 : RefPtr<SVGIRect> rect;
196 0 : rv = textFrame->GetExtentOfChar(this, charnum, getter_AddRefs(rect));
197 0 : return rect.forget();
198 : }
199 :
200 : float
201 0 : SVGTextContentElement::GetRotationOfChar(uint32_t charnum, ErrorResult& rv)
202 : {
203 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
204 :
205 0 : if (!textFrame) {
206 0 : rv.Throw(NS_ERROR_FAILURE);
207 0 : return 0.0f;
208 : }
209 :
210 : float rotation;
211 0 : rv = textFrame->GetRotationOfChar(this, charnum, &rotation);
212 0 : return rotation;
213 : }
214 :
215 : int32_t
216 0 : SVGTextContentElement::GetCharNumAtPosition(nsISVGPoint& aPoint)
217 : {
218 0 : SVGTextFrame* textFrame = GetSVGTextFrame();
219 0 : return textFrame ? textFrame->GetCharNumAtPosition(this, &aPoint) : -1;
220 : }
221 :
222 : } // namespace dom
223 : } // namespace mozilla
|