OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. | 2 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. |
3 * | 3 * |
4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
8 * | 8 * |
9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 17 matching lines...) Expand all Loading... |
28 | 28 |
29 namespace { | 29 namespace { |
30 | 30 |
31 void updateLayoutAttributes(LayoutSVGInlineText& text, unsigned& valueListPositi
on, const SVGCharacterDataMap& allCharactersMap) | 31 void updateLayoutAttributes(LayoutSVGInlineText& text, unsigned& valueListPositi
on, const SVGCharacterDataMap& allCharactersMap) |
32 { | 32 { |
33 SVGTextLayoutAttributes& attributes = *text.layoutAttributes(); | 33 SVGTextLayoutAttributes& attributes = *text.layoutAttributes(); |
34 attributes.clear(); | 34 attributes.clear(); |
35 | 35 |
36 const Vector<SVGTextMetrics>& metricsList = text.metricsList(); | 36 const Vector<SVGTextMetrics>& metricsList = text.metricsList(); |
37 auto metricsEnd = metricsList.end(); | 37 auto metricsEnd = metricsList.end(); |
38 unsigned surrogatePairCharacters = 0; | |
39 unsigned skippedWhitespace = 0; | |
40 unsigned currentPosition = 0; | 38 unsigned currentPosition = 0; |
41 for (auto metrics = metricsList.begin(); metrics != metricsEnd; currentPosit
ion += metrics->length(), ++metrics) { | 39 for (auto metrics = metricsList.begin(); metrics != metricsEnd; currentPosit
ion += metrics->length(), ++metrics) { |
42 if (metrics->isEmpty()) { | 40 if (metrics->isEmpty()) |
43 skippedWhitespace++; | |
44 continue; | 41 continue; |
45 } | |
46 | 42 |
47 unsigned currentValueListPosition = valueListPosition - skippedWhitespac
e - surrogatePairCharacters + currentPosition + 1; | 43 auto it = allCharactersMap.find(valueListPosition + 1); |
48 auto it = allCharactersMap.find(currentValueListPosition); | |
49 if (it != allCharactersMap.end()) | 44 if (it != allCharactersMap.end()) |
50 attributes.characterDataMap().set(currentPosition + 1, it->value); | 45 attributes.characterDataMap().set(currentPosition + 1, it->value); |
51 | 46 |
52 // At the moment, only surrogates will be length == 2 (or even > 1). | 47 // Increase the position in the value/attribute list with one for each |
53 if (metrics->length() == 2) | 48 // "character unit" (that will be displayed.) |
54 surrogatePairCharacters++; | 49 valueListPosition++; |
55 } | 50 } |
56 | |
57 // TODO(fs): currentPosition ought to always equal text.textLength() here. | |
58 valueListPosition += currentPosition - skippedWhitespace; | |
59 } | 51 } |
60 | 52 |
61 } // namespace | 53 } // namespace |
62 | 54 |
63 SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder() | 55 SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder() |
64 : m_textLength(0) | 56 : m_characterCount(0) |
65 { | 57 { |
66 } | 58 } |
67 | 59 |
68 void SVGTextLayoutAttributesBuilder::buildLayoutAttributes(LayoutSVGText& textRo
ot) const | 60 void SVGTextLayoutAttributesBuilder::buildLayoutAttributes(LayoutSVGText& textRo
ot) const |
69 { | 61 { |
70 unsigned valueListPosition = 0; | 62 unsigned valueListPosition = 0; |
71 LayoutObject* child = textRoot.firstChild(); | 63 LayoutObject* child = textRoot.firstChild(); |
72 while (child) { | 64 while (child) { |
73 if (child->isSVGInlineText()) { | 65 if (child->isSVGInlineText()) { |
74 updateLayoutAttributes(toLayoutSVGInlineText(*child), valueListPosit
ion, m_characterDataMap); | 66 updateLayoutAttributes(toLayoutSVGInlineText(*child), valueListPosit
ion, m_characterDataMap); |
75 } else if (child->isSVGInline()) { | 67 } else if (child->isSVGInline()) { |
76 // Visit children of text content elements. | 68 // Visit children of text content elements. |
77 if (LayoutObject* inlineChild = toLayoutSVGInline(child)->firstChild
()) { | 69 if (LayoutObject* inlineChild = toLayoutSVGInline(child)->firstChild
()) { |
78 child = inlineChild; | 70 child = inlineChild; |
79 continue; | 71 continue; |
80 } | 72 } |
81 } | 73 } |
82 child = child->nextInPreOrderAfterChildren(&textRoot); | 74 child = child->nextInPreOrderAfterChildren(&textRoot); |
83 } | 75 } |
84 } | 76 } |
85 | 77 |
86 void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRoot(LayoutSVGT
ext& textRoot) | 78 void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRoot(LayoutSVGT
ext& textRoot) |
87 { | 79 { |
88 m_characterDataMap.clear(); | 80 m_characterDataMap.clear(); |
89 | 81 |
90 if (m_textPositions.isEmpty()) { | 82 if (m_textPositions.isEmpty()) { |
91 m_textLength = 0; | 83 m_characterCount = 0; |
92 UChar lastCharacter = ' '; | 84 collectTextPositioningElements(textRoot); |
93 collectTextPositioningElements(textRoot, lastCharacter); | |
94 } | 85 } |
95 | 86 |
96 if (!m_textLength) | 87 if (!m_characterCount) |
97 return; | 88 return; |
98 | 89 |
99 buildCharacterDataMap(textRoot); | 90 buildCharacterDataMap(textRoot); |
100 buildLayoutAttributes(textRoot); | 91 buildLayoutAttributes(textRoot); |
101 } | 92 } |
102 | 93 |
103 static inline void processLayoutSVGInlineText(LayoutSVGInlineText* text, unsigne
d& atCharacter, UChar& lastCharacter) | 94 static inline unsigned countCharactersInTextNode(const LayoutSVGInlineText& text
) |
104 { | 95 { |
105 if (text->style()->whiteSpace() == PRE) { | 96 unsigned numCharacters = 0; |
106 atCharacter += text->textLength(); | 97 for (const SVGTextMetrics& metrics : text.metricsList()) { |
107 return; | 98 if (metrics.isEmpty()) |
| 99 continue; |
| 100 numCharacters++; |
108 } | 101 } |
109 | 102 return numCharacters; |
110 unsigned textLength = text->textLength(); | |
111 for (unsigned textPosition = 0; textPosition < textLength; ++textPosition) { | |
112 UChar currentCharacter = text->characterAt(textPosition); | |
113 if (currentCharacter == ' ' && lastCharacter == ' ') | |
114 continue; | |
115 | |
116 lastCharacter = currentCharacter; | |
117 ++atCharacter; | |
118 } | |
119 } | 103 } |
120 | 104 |
121 static SVGTextPositioningElement* positioningElementFromLayoutObject(LayoutObjec
t& layoutObject) | 105 static SVGTextPositioningElement* positioningElementFromLayoutObject(LayoutObjec
t& layoutObject) |
122 { | 106 { |
123 ASSERT(layoutObject.isSVGText() || layoutObject.isSVGInline()); | 107 ASSERT(layoutObject.isSVGText() || layoutObject.isSVGInline()); |
124 | 108 |
125 Node* node = layoutObject.node(); | 109 Node* node = layoutObject.node(); |
126 ASSERT(node); | 110 ASSERT(node); |
127 ASSERT(node->isSVGElement()); | 111 ASSERT(node->isSVGElement()); |
128 | 112 |
129 return isSVGTextPositioningElement(*node) ? toSVGTextPositioningElement(node
) : nullptr; | 113 return isSVGTextPositioningElement(*node) ? toSVGTextPositioningElement(node
) : nullptr; |
130 } | 114 } |
131 | 115 |
132 void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(LayoutBoxMod
elObject& start, UChar& lastCharacter) | 116 void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(LayoutBoxMod
elObject& start) |
133 { | 117 { |
134 ASSERT(!start.isSVGText() || m_textPositions.isEmpty()); | 118 ASSERT(!start.isSVGText() || m_textPositions.isEmpty()); |
135 | 119 |
136 for (LayoutObject* child = start.slowFirstChild(); child; child = child->nex
tSibling()) { | 120 for (LayoutObject* child = start.slowFirstChild(); child; child = child->nex
tSibling()) { |
137 if (child->isSVGInlineText()) { | 121 if (child->isSVGInlineText()) { |
138 processLayoutSVGInlineText(toLayoutSVGInlineText(child), m_textLengt
h, lastCharacter); | 122 m_characterCount += countCharactersInTextNode(toLayoutSVGInlineText(
*child)); |
139 continue; | 123 continue; |
140 } | 124 } |
141 | 125 |
142 if (!child->isSVGInline()) | 126 if (!child->isSVGInline()) |
143 continue; | 127 continue; |
144 | 128 |
145 LayoutSVGInline& inlineChild = toLayoutSVGInline(*child); | 129 LayoutSVGInline& inlineChild = toLayoutSVGInline(*child); |
146 SVGTextPositioningElement* element = positioningElementFromLayoutObject(
inlineChild); | 130 SVGTextPositioningElement* element = positioningElementFromLayoutObject(
inlineChild); |
147 unsigned atPosition = m_textPositions.size(); | 131 unsigned atPosition = m_textPositions.size(); |
148 if (element) | 132 if (element) |
149 m_textPositions.append(TextPosition(element, m_textLength)); | 133 m_textPositions.append(TextPosition(element, m_characterCount)); |
150 | 134 |
151 collectTextPositioningElements(inlineChild, lastCharacter); | 135 collectTextPositioningElements(inlineChild); |
152 | 136 |
153 if (!element) | 137 if (!element) |
154 continue; | 138 continue; |
155 | 139 |
156 // Update text position, after we're back from recursion. | 140 // Update text position, after we're back from recursion. |
157 TextPosition& position = m_textPositions[atPosition]; | 141 TextPosition& position = m_textPositions[atPosition]; |
158 ASSERT(!position.length); | 142 ASSERT(!position.length); |
159 position.length = m_textLength - position.start; | 143 position.length = m_characterCount - position.start; |
160 } | 144 } |
161 } | 145 } |
162 | 146 |
163 void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(LayoutSVGText& textRo
ot) | 147 void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(LayoutSVGText& textRo
ot) |
164 { | 148 { |
165 SVGTextPositioningElement* outermostTextElement = positioningElementFromLayo
utObject(textRoot); | 149 SVGTextPositioningElement* outermostTextElement = positioningElementFromLayo
utObject(textRoot); |
166 ASSERT(outermostTextElement); | 150 ASSERT(outermostTextElement); |
167 | 151 |
168 // Grab outermost <text> element value lists and insert them in the characte
r data map. | 152 // Grab outermost <text> element value lists and insert them in the characte
r data map. |
169 TextPosition wholeTextPosition(outermostTextElement, 0, m_textLength); | 153 TextPosition wholeTextPosition(outermostTextElement, 0, m_characterCount); |
170 fillCharacterDataMap(wholeTextPosition); | 154 fillCharacterDataMap(wholeTextPosition); |
171 | 155 |
172 // Fill character data map using child text positioning elements in top-down
order. | 156 // Fill character data map using child text positioning elements in top-down
order. |
173 unsigned size = m_textPositions.size(); | 157 unsigned size = m_textPositions.size(); |
174 for (unsigned i = 0; i < size; ++i) | 158 for (unsigned i = 0; i < size; ++i) |
175 fillCharacterDataMap(m_textPositions[i]); | 159 fillCharacterDataMap(m_textPositions[i]); |
176 | 160 |
177 // Handle x/y default attributes. | 161 // Handle x/y default attributes. |
178 SVGCharacterData& data = m_characterDataMap.add(1, SVGCharacterData()).store
dValue->value; | 162 SVGCharacterData& data = m_characterDataMap.add(1, SVGCharacterData()).store
dValue->value; |
179 if (SVGTextLayoutAttributes::isEmptyValue(data.x)) | 163 if (SVGTextLayoutAttributes::isEmptyValue(data.x)) |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 attrLists.updateCharacterData(i, data); | 246 attrLists.updateCharacterData(i, data); |
263 } | 247 } |
264 } | 248 } |
265 | 249 |
266 DEFINE_TRACE(SVGTextLayoutAttributesBuilder::TextPosition) | 250 DEFINE_TRACE(SVGTextLayoutAttributesBuilder::TextPosition) |
267 { | 251 { |
268 visitor->trace(element); | 252 visitor->trace(element); |
269 } | 253 } |
270 | 254 |
271 } // namespace blink | 255 } // namespace blink |
OLD | NEW |