OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | 2 * Copyright (C) Research In Motion Limited 2010. 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 |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 * Library General Public License for more details. | 12 * Library General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU Library General Public License | 14 * You should have received a copy of the GNU Library General Public License |
15 * along with this library; see the file COPYING.LIB. If not, write to | 15 * along with this library; see the file COPYING.LIB. If not, write to |
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 * Boston, MA 02110-1301, USA. | 17 * Boston, MA 02110-1301, USA. |
18 */ | 18 */ |
19 | 19 |
20 #include "core/layout/svg/SVGTextChunkBuilder.h" | 20 #include "core/layout/svg/SVGTextChunkBuilder.h" |
21 | 21 |
22 #include "core/layout/api/LineLayoutSVGInlineText.h" | 22 #include "core/layout/api/LineLayoutSVGInlineText.h" |
23 #include "core/layout/svg/LayoutSVGInlineText.h" | |
24 #include "core/layout/svg/line/SVGInlineTextBox.h" | 23 #include "core/layout/svg/line/SVGInlineTextBox.h" |
25 #include "core/svg/SVGLengthContext.h" | 24 #include "core/svg/SVGLengthContext.h" |
26 #include "core/svg/SVGTextContentElement.h" | 25 #include "core/svg/SVGTextContentElement.h" |
27 #include "platform/transforms/AffineTransform.h" | |
28 | 26 |
29 namespace blink { | 27 namespace blink { |
30 | 28 |
31 namespace { | 29 namespace { |
32 | 30 |
33 float calculateTextAnchorShift(const ComputedStyle& style, float length) | 31 float calculateTextAnchorShift(const ComputedStyle& style, float length) |
34 { | 32 { |
35 bool isLTR = style.isLeftToRightDirection(); | 33 bool isLTR = style.isLeftToRightDirection(); |
36 switch (style.svgStyle().textAnchor()) { | 34 switch (style.svgStyle().textAnchor()) { |
37 default: | 35 default: |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 ChunkLengthAccumulator lengthAccumulator(!style.isHorizontalWritingMode()); | 163 ChunkLengthAccumulator lengthAccumulator(!style.isHorizontalWritingMode()); |
166 lengthAccumulator.processRange(boxStart, boxEnd); | 164 lengthAccumulator.processRange(boxStart, boxEnd); |
167 | 165 |
168 // Handle text-anchor as additional start offset for text paths. | 166 // Handle text-anchor as additional start offset for text paths. |
169 m_totalTextAnchorShift += calculateTextAnchorShift(style, lengthAccumulator.
length()); | 167 m_totalTextAnchorShift += calculateTextAnchorShift(style, lengthAccumulator.
length()); |
170 | 168 |
171 m_totalLength += lengthAccumulator.length(); | 169 m_totalLength += lengthAccumulator.length(); |
172 m_totalCharacters += lengthAccumulator.numCharacters(); | 170 m_totalCharacters += lengthAccumulator.numCharacters(); |
173 } | 171 } |
174 | 172 |
175 static void buildSpacingAndGlyphsTransform(bool isVerticalText, float scale, con
st SVGTextFragment& fragment, AffineTransform& spacingAndGlyphsTransform) | 173 static float computeTextLengthBias(const SVGTextFragment& fragment, float scale) |
176 { | 174 { |
177 spacingAndGlyphsTransform.translate(fragment.x, fragment.y); | 175 float initialPosition = fragment.isVertical ? fragment.y : fragment.x; |
178 | 176 return initialPosition + scale * -initialPosition; |
179 if (isVerticalText) | |
180 spacingAndGlyphsTransform.scaleNonUniform(1, scale); | |
181 else | |
182 spacingAndGlyphsTransform.scaleNonUniform(scale, 1); | |
183 | |
184 spacingAndGlyphsTransform.translate(-fragment.x, -fragment.y); | |
185 } | 177 } |
186 | 178 |
187 void SVGTextChunkBuilder::handleTextChunk(BoxListConstIterator boxStart, BoxList
ConstIterator boxEnd) | 179 void SVGTextChunkBuilder::handleTextChunk(BoxListConstIterator boxStart, BoxList
ConstIterator boxEnd) |
188 { | 180 { |
189 ASSERT(*boxStart); | 181 ASSERT(*boxStart); |
190 | 182 |
191 const LineLayoutSVGInlineText textLineLayout = LineLayoutSVGInlineText((*box
Start)->lineLayoutItem()); | 183 const LineLayoutSVGInlineText textLineLayout = LineLayoutSVGInlineText((*box
Start)->lineLayoutItem()); |
192 const ComputedStyle& style = textLineLayout.styleRef(); | 184 const ComputedStyle& style = textLineLayout.styleRef(); |
193 | 185 |
194 // Handle 'lengthAdjust' property. | 186 // Handle 'lengthAdjust' property. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 | 221 |
230 // Fragments have been adjusted, we have to recalculate the chunk | 222 // Fragments have been adjusted, we have to recalculate the chunk |
231 // length, to be able to apply the text-anchor shift. | 223 // length, to be able to apply the text-anchor shift. |
232 if (processTextAnchor) { | 224 if (processTextAnchor) { |
233 lengthAccumulator.reset(); | 225 lengthAccumulator.reset(); |
234 lengthAccumulator.processRange(boxStart, boxEnd); | 226 lengthAccumulator.processRange(boxStart, boxEnd); |
235 } | 227 } |
236 } else { | 228 } else { |
237 ASSERT(lengthAdjust == SVGLengthAdjustSpacingAndGlyphs); | 229 ASSERT(lengthAdjust == SVGLengthAdjustSpacingAndGlyphs); |
238 float textLengthScale = desiredTextLength / chunkLength; | 230 float textLengthScale = desiredTextLength / chunkLength; |
239 AffineTransform spacingAndGlyphsTransform; | 231 float textLengthBias = 0; |
240 | 232 |
241 bool foundFirstFragment = false; | 233 bool foundFirstFragment = false; |
242 for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { | 234 for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { |
243 SVGInlineTextBox* textBox = *boxIter; | 235 SVGInlineTextBox* textBox = *boxIter; |
244 Vector<SVGTextFragment>& fragments = textBox->textFragments(); | 236 Vector<SVGTextFragment>& fragments = textBox->textFragments(); |
245 if (fragments.isEmpty()) | 237 if (fragments.isEmpty()) |
246 continue; | 238 continue; |
247 | 239 |
248 if (!foundFirstFragment) { | 240 if (!foundFirstFragment) { |
249 foundFirstFragment = true; | 241 foundFirstFragment = true; |
250 buildSpacingAndGlyphsTransform(isVerticalText, textLengthSca
le, fragments.first(), spacingAndGlyphsTransform); | 242 textLengthBias = computeTextLengthBias(fragments.first(), te
xtLengthScale); |
251 } | 243 } |
252 | 244 |
253 applyTextLengthScaleAdjustment(spacingAndGlyphsTransform, fragme
nts); | 245 applyTextLengthScaleAdjustment(textLengthScale, textLengthBias,
fragments); |
254 } | 246 } |
255 } | 247 } |
256 } | 248 } |
257 | 249 |
258 if (!processTextAnchor) | 250 if (!processTextAnchor) |
259 return; | 251 return; |
260 | 252 |
261 float textAnchorShift = calculateTextAnchorShift(style, lengthAccumulator.le
ngth()); | 253 float textAnchorShift = calculateTextAnchorShift(style, lengthAccumulator.le
ngth()); |
262 for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { | 254 for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { |
263 Vector<SVGTextFragment>& fragments = (*boxIter)->textFragments(); | 255 Vector<SVGTextFragment>& fragments = (*boxIter)->textFragments(); |
264 if (fragments.isEmpty()) | 256 if (fragments.isEmpty()) |
265 continue; | 257 continue; |
266 processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments); | 258 processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments); |
267 } | 259 } |
268 } | 260 } |
269 | 261 |
270 void SVGTextChunkBuilder::processTextLengthSpacingCorrection(bool isVerticalText
, float textLengthShift, Vector<SVGTextFragment>& fragments, unsigned& atCharact
er) | 262 void SVGTextChunkBuilder::processTextLengthSpacingCorrection(bool isVerticalText
, float textLengthShift, Vector<SVGTextFragment>& fragments, unsigned& atCharact
er) |
271 { | 263 { |
272 for (SVGTextFragment& fragment : fragments) { | 264 for (SVGTextFragment& fragment : fragments) { |
273 if (isVerticalText) | 265 if (isVerticalText) |
274 fragment.y += textLengthShift * atCharacter; | 266 fragment.y += textLengthShift * atCharacter; |
275 else | 267 else |
276 fragment.x += textLengthShift * atCharacter; | 268 fragment.x += textLengthShift * atCharacter; |
277 | 269 |
278 atCharacter += fragment.length; | 270 atCharacter += fragment.length; |
279 } | 271 } |
280 } | 272 } |
281 | 273 |
282 void SVGTextChunkBuilder::applyTextLengthScaleAdjustment(const AffineTransform&
spacingAndGlyphsTransform, Vector<SVGTextFragment>& fragments) | 274 void SVGTextChunkBuilder::applyTextLengthScaleAdjustment(float textLengthScale,
float textLengthBias, Vector<SVGTextFragment>& fragments) |
283 { | 275 { |
284 for (SVGTextFragment& fragment : fragments) { | 276 for (SVGTextFragment& fragment : fragments) { |
285 ASSERT(fragment.lengthAdjustTransform.isIdentity()); | 277 ASSERT(fragment.lengthAdjustScale == 1); |
286 fragment.lengthAdjustTransform = spacingAndGlyphsTransform; | 278 fragment.lengthAdjustScale = textLengthScale; |
| 279 fragment.lengthAdjustBias = textLengthBias; |
287 } | 280 } |
288 } | 281 } |
289 | 282 |
290 void SVGTextChunkBuilder::processTextAnchorCorrection(bool isVerticalText, float
textAnchorShift, Vector<SVGTextFragment>& fragments) | 283 void SVGTextChunkBuilder::processTextAnchorCorrection(bool isVerticalText, float
textAnchorShift, Vector<SVGTextFragment>& fragments) |
291 { | 284 { |
292 for (SVGTextFragment& fragment : fragments) { | 285 for (SVGTextFragment& fragment : fragments) { |
293 if (isVerticalText) | 286 if (isVerticalText) |
294 fragment.y += textAnchorShift; | 287 fragment.y += textAnchorShift; |
295 else | 288 else |
296 fragment.x += textAnchorShift; | 289 fragment.x += textAnchorShift; |
297 } | 290 } |
298 } | 291 } |
299 | 292 |
300 } | 293 } |
OLD | NEW |