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