Chromium Code Reviews| 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 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #include "core/layout/svg/SVGTextChunkBuilder.h" | 21 #include "core/layout/svg/SVGTextChunkBuilder.h" |
| 22 | 22 |
| 23 #include "core/layout/svg/LayoutSVGInlineText.h" | 23 #include "core/layout/svg/LayoutSVGInlineText.h" |
| 24 #include "core/layout/svg/SVGTextChunk.h" | 24 #include "core/layout/svg/SVGTextChunk.h" |
| 25 #include "core/layout/svg/line/SVGInlineTextBox.h" | 25 #include "core/layout/svg/line/SVGInlineTextBox.h" |
| 26 #include "core/svg/SVGLengthContext.h" | 26 #include "core/svg/SVGLengthContext.h" |
| 27 #include "core/svg/SVGTextContentElement.h" | 27 #include "core/svg/SVGTextContentElement.h" |
| 28 | 28 |
| 29 namespace blink { | 29 namespace blink { |
| 30 | 30 |
| 31 SVGTextChunkBuilder::SVGTextChunkBuilder() | 31 namespace { |
|
pdr.
2015/05/28 22:00:03
Is this empty namespace needed?
fs
2015/05/29 09:26:36
Not strictly I suppose, but it provides a neat pac
| |
| 32 | |
| 33 SVGTextChunk createTextChunk(const SVGInlineTextBox* textBox) | |
|
pdr.
2015/05/28 22:00:03
Should this be static?
Can you change the textBox
fs
2015/05/29 09:26:36
The unnamed namespace will have that effect - and
| |
| 32 { | 34 { |
| 33 } | |
| 34 | |
| 35 void SVGTextChunkBuilder::processTextChunks(const Vector<SVGInlineTextBox*>& lin eLayoutBoxes) | |
| 36 { | |
| 37 if (lineLayoutBoxes.isEmpty()) | |
| 38 return; | |
| 39 | |
| 40 bool foundStart = false; | |
| 41 unsigned lastChunkStartPosition = 0; | |
| 42 unsigned boxPosition = 0; | |
| 43 unsigned boxCount = lineLayoutBoxes.size(); | |
| 44 for (; boxPosition < boxCount; ++boxPosition) { | |
| 45 SVGInlineTextBox* textBox = lineLayoutBoxes[boxPosition]; | |
| 46 if (!textBox->startsNewTextChunk()) | |
| 47 continue; | |
| 48 | |
| 49 if (!foundStart) { | |
| 50 foundStart = true; | |
| 51 } else { | |
| 52 ASSERT(boxPosition > lastChunkStartPosition); | |
| 53 handleTextChunk(lineLayoutBoxes, lastChunkStartPosition, boxPosition ); | |
| 54 } | |
| 55 lastChunkStartPosition = boxPosition; | |
| 56 } | |
| 57 | |
| 58 if (!foundStart) | |
| 59 return; | |
| 60 | |
| 61 if (boxPosition - lastChunkStartPosition > 0) | |
| 62 handleTextChunk(lineLayoutBoxes, lastChunkStartPosition, boxPosition); | |
| 63 } | |
| 64 | |
| 65 SVGTextPathChunkBuilder::SVGTextPathChunkBuilder() | |
| 66 : SVGTextChunkBuilder() | |
| 67 , m_totalLength(0) | |
| 68 , m_totalCharacters(0) | |
| 69 , m_totalTextAnchorShift(0) | |
| 70 { | |
| 71 } | |
| 72 | |
| 73 static SVGTextChunk createTextChunk(const Vector<SVGInlineTextBox*>& lineLayoutB oxes, unsigned boxStart, unsigned boxCount) | |
| 74 { | |
| 75 SVGInlineTextBox* textBox = lineLayoutBoxes[boxStart]; | |
| 76 ASSERT(textBox); | 35 ASSERT(textBox); |
| 77 | 36 |
| 78 LayoutSVGInlineText& textLayoutObject = toLayoutSVGInlineText(textBox->layou tObject()); | 37 LayoutSVGInlineText& textLayoutObject = toLayoutSVGInlineText(textBox->layou tObject()); |
| 79 | 38 const ComputedStyle& style = textLayoutObject.styleRef(); |
| 80 const ComputedStyle& style = toLayoutSVGInlineText(textBox->layoutObject()). styleRef(); | |
| 81 | |
| 82 const SVGComputedStyle& svgStyle = style.svgStyle(); | 39 const SVGComputedStyle& svgStyle = style.svgStyle(); |
| 83 | 40 |
| 84 // Build chunk style flags. | 41 // Build chunk style flags. |
| 85 unsigned chunkStyle = SVGTextChunk::DefaultStyle; | 42 unsigned chunkStyle = SVGTextChunk::DefaultStyle; |
| 86 | 43 |
| 87 // Handle 'direction' property. | 44 // Handle 'direction' property. |
| 88 if (!style.isLeftToRightDirection()) | 45 if (!style.isLeftToRightDirection()) |
| 89 chunkStyle |= SVGTextChunk::RightToLeftText; | 46 chunkStyle |= SVGTextChunk::RightToLeftText; |
| 90 | 47 |
| 91 // Handle 'writing-mode' property. | 48 // Handle 'writing-mode' property. |
| 92 if (svgStyle.isVerticalWritingMode()) | 49 if (svgStyle.isVerticalWritingMode()) |
| 93 chunkStyle |= SVGTextChunk::VerticalText; | 50 chunkStyle |= SVGTextChunk::VerticalText; |
| 94 | 51 |
| 95 // Handle 'text-anchor' property. | 52 // Handle 'text-anchor' property. |
| 96 switch (svgStyle.textAnchor()) { | 53 switch (svgStyle.textAnchor()) { |
| 97 case TA_START: | 54 case TA_START: |
| 98 break; | 55 break; |
| 99 case TA_MIDDLE: | 56 case TA_MIDDLE: |
| 100 chunkStyle |= SVGTextChunk::MiddleAnchor; | 57 chunkStyle |= SVGTextChunk::MiddleAnchor; |
| 101 break; | 58 break; |
| 102 case TA_END: | 59 case TA_END: |
| 103 chunkStyle |= SVGTextChunk::EndAnchor; | 60 chunkStyle |= SVGTextChunk::EndAnchor; |
| 104 break; | 61 break; |
| 105 }; | 62 } |
| 106 | 63 |
| 107 // Handle 'lengthAdjust' property. | 64 // Handle 'lengthAdjust' property. |
| 108 float desiredTextLength = 0; | 65 float desiredTextLength = 0; |
| 109 if (SVGTextContentElement* textContentElement = SVGTextContentElement::eleme ntFromLayoutObject(textLayoutObject.parent())) { | 66 if (SVGTextContentElement* textContentElement = SVGTextContentElement::eleme ntFromLayoutObject(textLayoutObject.parent())) { |
| 110 SVGLengthContext lengthContext(textContentElement); | 67 SVGLengthContext lengthContext(textContentElement); |
| 111 if (textContentElement->textLengthIsSpecifiedByUser()) | 68 if (textContentElement->textLengthIsSpecifiedByUser()) |
| 112 desiredTextLength = textContentElement->textLength()->currentValue() ->value(lengthContext); | 69 desiredTextLength = textContentElement->textLength()->currentValue() ->value(lengthContext); |
| 113 else | 70 else |
| 114 desiredTextLength = 0; | 71 desiredTextLength = 0; |
| 115 | 72 |
| 116 switch (textContentElement->lengthAdjust()->currentValue()->enumValue()) { | 73 switch (textContentElement->lengthAdjust()->currentValue()->enumValue()) { |
| 117 case SVGLengthAdjustUnknown: | 74 case SVGLengthAdjustUnknown: |
| 118 break; | 75 break; |
| 119 case SVGLengthAdjustSpacing: | 76 case SVGLengthAdjustSpacing: |
| 120 chunkStyle |= SVGTextChunk::LengthAdjustSpacing; | 77 chunkStyle |= SVGTextChunk::LengthAdjustSpacing; |
| 121 break; | 78 break; |
| 122 case SVGLengthAdjustSpacingAndGlyphs: | 79 case SVGLengthAdjustSpacingAndGlyphs: |
| 123 chunkStyle |= SVGTextChunk::LengthAdjustSpacingAndGlyphs; | 80 chunkStyle |= SVGTextChunk::LengthAdjustSpacingAndGlyphs; |
| 124 break; | 81 break; |
| 125 }; | 82 } |
| 126 } | 83 } |
| 127 | 84 |
| 128 SVGTextChunk chunk(chunkStyle, desiredTextLength); | 85 return SVGTextChunk(chunkStyle, desiredTextLength); |
| 129 | |
| 130 Vector<SVGInlineTextBox*>& boxes = chunk.boxes(); | |
| 131 for (unsigned i = boxStart; i < boxStart + boxCount; ++i) | |
| 132 boxes.append(lineLayoutBoxes[i]); | |
| 133 | |
| 134 return chunk; | |
| 135 } | 86 } |
| 136 | 87 |
| 137 void SVGTextPathChunkBuilder::handleTextChunk(const Vector<SVGInlineTextBox*>& b oxes, unsigned boxStart, unsigned boxEnd) | 88 class ChunkLengthAccumulator { |
| 89 public: | |
| 90 ChunkLengthAccumulator(bool isVertical) | |
| 91 : m_numCharacters(0) | |
| 92 , m_length(0) | |
| 93 , m_isVertical(isVertical) | |
| 94 { | |
| 95 } | |
| 96 | |
| 97 typedef Vector<SVGInlineTextBox*>::const_iterator BoxListConstIterator; | |
| 98 | |
| 99 void processRange(BoxListConstIterator boxStart, BoxListConstIterator boxEnd ); | |
| 100 void reset() | |
| 101 { | |
| 102 m_numCharacters = 0; | |
| 103 m_length = 0; | |
| 104 } | |
| 105 | |
| 106 float length() const { return m_length; } | |
| 107 unsigned numCharacters() const { return m_numCharacters; } | |
| 108 | |
| 109 private: | |
| 110 unsigned m_numCharacters; | |
| 111 float m_length; | |
| 112 const bool m_isVertical; | |
| 113 }; | |
| 114 | |
| 115 void ChunkLengthAccumulator::processRange(BoxListConstIterator boxStart, BoxList ConstIterator boxEnd) | |
| 138 { | 116 { |
| 139 SVGTextChunk chunk = createTextChunk(boxes, boxStart, boxEnd - boxStart); | 117 SVGTextFragment* lastFragment = nullptr; |
| 118 for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { | |
| 119 for (SVGTextFragment& fragment : (*boxIter)->textFragments()) { | |
| 120 m_numCharacters += fragment.length; | |
| 140 | 121 |
| 141 float length = 0; | 122 if (m_isVertical) |
| 142 unsigned characters = 0; | 123 m_length += fragment.height; |
| 143 chunk.calculateLength(length, characters); | 124 else |
| 125 m_length += fragment.width; | |
| 126 | |
| 127 if (!lastFragment) { | |
| 128 lastFragment = &fragment; | |
| 129 continue; | |
| 130 } | |
| 131 | |
| 132 // Respect gap between chunks. | |
| 133 if (m_isVertical) | |
| 134 m_length += fragment.y - (lastFragment->y + lastFragment->height ); | |
| 135 else | |
| 136 m_length += fragment.x - (lastFragment->x + lastFragment->width) ; | |
| 137 | |
| 138 lastFragment = &fragment; | |
| 139 } | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 } | |
| 144 | |
| 145 SVGTextChunkBuilder::SVGTextChunkBuilder() | |
| 146 { | |
| 147 } | |
| 148 | |
| 149 void SVGTextChunkBuilder::processTextChunks(const Vector<SVGInlineTextBox*>& lin eLayoutBoxes) | |
| 150 { | |
| 151 if (lineLayoutBoxes.isEmpty()) | |
| 152 return; | |
| 153 | |
| 154 bool foundStart = false; | |
| 155 auto boxIter = lineLayoutBoxes.begin(); | |
| 156 auto endBox = lineLayoutBoxes.end(); | |
| 157 auto chunkStartBox = boxIter; | |
| 158 for (; boxIter != endBox; ++boxIter) { | |
|
pdr.
2015/05/28 22:00:03
Not your fault, but can you switch this a fancy fo
fs
2015/05/29 09:26:36
I think that should be possible eventually, but fo
| |
| 159 if (!(*boxIter)->startsNewTextChunk()) | |
| 160 continue; | |
| 161 | |
| 162 if (!foundStart) { | |
| 163 foundStart = true; | |
| 164 } else { | |
| 165 ASSERT(boxIter != chunkStartBox); | |
| 166 handleTextChunk(chunkStartBox, boxIter); | |
| 167 } | |
| 168 chunkStartBox = boxIter; | |
| 169 } | |
| 170 | |
| 171 if (!foundStart) | |
| 172 return; | |
| 173 | |
| 174 if (boxIter != chunkStartBox) | |
| 175 handleTextChunk(chunkStartBox, boxIter); | |
| 176 } | |
| 177 | |
| 178 SVGTextPathChunkBuilder::SVGTextPathChunkBuilder() | |
| 179 : SVGTextChunkBuilder() | |
| 180 , m_totalLength(0) | |
| 181 , m_totalCharacters(0) | |
| 182 , m_totalTextAnchorShift(0) | |
| 183 { | |
| 184 } | |
| 185 | |
| 186 void SVGTextPathChunkBuilder::handleTextChunk(BoxListConstIterator boxStart, Box ListConstIterator boxEnd) | |
| 187 { | |
| 188 SVGTextChunk chunk = createTextChunk(*boxStart); | |
| 189 | |
| 190 ChunkLengthAccumulator lengthAccumulator(chunk.isVerticalText()); | |
| 191 lengthAccumulator.processRange(boxStart, boxEnd); | |
| 144 | 192 |
| 145 // Handle text-anchor as additional start offset for text paths. | 193 // Handle text-anchor as additional start offset for text paths. |
| 146 m_totalTextAnchorShift += chunk.calculateTextAnchorShift(length); | 194 m_totalTextAnchorShift += chunk.calculateTextAnchorShift(lengthAccumulator.l ength()); |
| 147 | 195 |
| 148 m_totalLength += length; | 196 m_totalLength += lengthAccumulator.length(); |
| 149 m_totalCharacters += characters; | 197 m_totalCharacters += lengthAccumulator.numCharacters(); |
| 150 } | 198 } |
| 151 | 199 |
| 152 static void buildSpacingAndGlyphsTransform(bool isVerticalText, float scale, con st SVGTextFragment& fragment, AffineTransform& spacingAndGlyphsTransform) | 200 static void buildSpacingAndGlyphsTransform(bool isVerticalText, float scale, con st SVGTextFragment& fragment, AffineTransform& spacingAndGlyphsTransform) |
| 153 { | 201 { |
| 154 spacingAndGlyphsTransform.translate(fragment.x, fragment.y); | 202 spacingAndGlyphsTransform.translate(fragment.x, fragment.y); |
| 155 | 203 |
| 156 if (isVerticalText) | 204 if (isVerticalText) |
| 157 spacingAndGlyphsTransform.scaleNonUniform(1, scale); | 205 spacingAndGlyphsTransform.scaleNonUniform(1, scale); |
| 158 else | 206 else |
| 159 spacingAndGlyphsTransform.scaleNonUniform(scale, 1); | 207 spacingAndGlyphsTransform.scaleNonUniform(scale, 1); |
| 160 | 208 |
| 161 spacingAndGlyphsTransform.translate(-fragment.x, -fragment.y); | 209 spacingAndGlyphsTransform.translate(-fragment.x, -fragment.y); |
| 162 } | 210 } |
| 163 | 211 |
| 164 void SVGTextChunkBuilder::handleTextChunk(const Vector<SVGInlineTextBox*>& lineB oxes, unsigned boxStart, unsigned boxEnd) | 212 void SVGTextChunkBuilder::handleTextChunk(BoxListConstIterator boxStart, BoxList ConstIterator boxEnd) |
| 165 { | 213 { |
| 166 SVGTextChunk chunk = createTextChunk(lineBoxes, boxStart, boxEnd - boxStart) ; | 214 SVGTextChunk chunk = createTextChunk(*boxStart); |
| 167 | 215 |
| 168 bool processTextLength = chunk.hasDesiredTextLength(); | 216 bool processTextLength = chunk.hasDesiredTextLength(); |
| 169 bool processTextAnchor = chunk.hasTextAnchor(); | 217 bool processTextAnchor = chunk.hasTextAnchor(); |
| 170 if (!processTextAnchor && !processTextLength) | 218 if (!processTextAnchor && !processTextLength) |
| 171 return; | 219 return; |
| 172 | 220 |
| 173 const Vector<SVGInlineTextBox*>& boxes = chunk.boxes(); | 221 bool isVerticalText = chunk.isVerticalText(); |
| 174 unsigned boxCount = boxes.size(); | |
| 175 if (!boxCount) | |
| 176 return; | |
| 177 | 222 |
| 178 // Calculate absolute length of whole text chunk (starting from text box 'st art', spanning 'length' text boxes). | 223 // Calculate absolute length of whole text chunk (starting from text box 'st art', spanning 'length' text boxes). |
| 179 float chunkLength = 0; | 224 ChunkLengthAccumulator lengthAccumulator(isVerticalText); |
| 180 unsigned chunkCharacters = 0; | 225 lengthAccumulator.processRange(boxStart, boxEnd); |
| 181 chunk.calculateLength(chunkLength, chunkCharacters); | |
| 182 | 226 |
| 183 bool isVerticalText = chunk.isVerticalText(); | |
| 184 if (processTextLength) { | 227 if (processTextLength) { |
| 228 float chunkLength = lengthAccumulator.length(); | |
| 185 if (chunk.hasLengthAdjustSpacing()) { | 229 if (chunk.hasLengthAdjustSpacing()) { |
| 186 float textLengthShift = (chunk.desiredTextLength() - chunkLength) / chunkCharacters; | 230 float textLengthShift = (chunk.desiredTextLength() - chunkLength) / lengthAccumulator.numCharacters(); |
| 187 unsigned atCharacter = 0; | 231 unsigned atCharacter = 0; |
| 188 for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition ) { | 232 for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { |
| 189 Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFra gments(); | 233 Vector<SVGTextFragment>& fragments = (*boxIter)->textFragments() ; |
| 190 if (fragments.isEmpty()) | 234 if (fragments.isEmpty()) |
| 191 continue; | 235 continue; |
| 192 processTextLengthSpacingCorrection(isVerticalText, textLengthShi ft, fragments, atCharacter); | 236 processTextLengthSpacingCorrection(isVerticalText, textLengthShi ft, fragments, atCharacter); |
| 193 } | 237 } |
| 238 | |
| 239 // Fragments have been adjusted, we have to recalculate the chunk | |
| 240 // length, to be able to apply the text-anchor shift. | |
| 241 if (processTextAnchor) { | |
|
pdr.
2015/05/28 22:00:03
(Probably for another patch)
I think this addition
fs
2015/05/29 09:26:36
Yepp, I've been thinking so too, but I'll leave th
| |
| 242 lengthAccumulator.reset(); | |
| 243 lengthAccumulator.processRange(boxStart, boxEnd); | |
| 244 } | |
| 194 } else { | 245 } else { |
| 195 ASSERT(chunk.hasLengthAdjustSpacingAndGlyphs()); | 246 ASSERT(chunk.hasLengthAdjustSpacingAndGlyphs()); |
| 196 float textLengthScale = chunk.desiredTextLength() / chunkLength; | 247 float textLengthScale = chunk.desiredTextLength() / chunkLength; |
| 197 AffineTransform spacingAndGlyphsTransform; | 248 AffineTransform spacingAndGlyphsTransform; |
| 198 | 249 |
| 199 bool foundFirstFragment = false; | 250 bool foundFirstFragment = false; |
| 200 for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition ) { | 251 for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { |
| 201 SVGInlineTextBox* textBox = boxes[boxPosition]; | 252 SVGInlineTextBox* textBox = *boxIter; |
| 202 Vector<SVGTextFragment>& fragments = textBox->textFragments(); | 253 Vector<SVGTextFragment>& fragments = textBox->textFragments(); |
| 203 if (fragments.isEmpty()) | 254 if (fragments.isEmpty()) |
| 204 continue; | 255 continue; |
| 205 | 256 |
| 206 if (!foundFirstFragment) { | 257 if (!foundFirstFragment) { |
| 207 foundFirstFragment = true; | 258 foundFirstFragment = true; |
| 208 buildSpacingAndGlyphsTransform(isVerticalText, textLengthSca le, fragments.first(), spacingAndGlyphsTransform); | 259 buildSpacingAndGlyphsTransform(isVerticalText, textLengthSca le, fragments.first(), spacingAndGlyphsTransform); |
| 209 } | 260 } |
| 210 | 261 |
| 211 m_textBoxTransformations.set(textBox, spacingAndGlyphsTransform) ; | 262 m_textBoxTransformations.set(textBox, spacingAndGlyphsTransform) ; |
| 212 } | 263 } |
| 213 } | 264 } |
| 214 } | 265 } |
| 215 | 266 |
| 216 if (!processTextAnchor) | 267 if (!processTextAnchor) |
| 217 return; | 268 return; |
| 218 | 269 |
| 219 // If we previously applied a lengthAdjust="spacing" correction, we have to recalculate the chunk length, to be able to apply the text-anchor shift. | 270 float textAnchorShift = chunk.calculateTextAnchorShift(lengthAccumulator.len gth()); |
| 220 if (processTextLength && chunk.hasLengthAdjustSpacing()) { | 271 for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) { |
| 221 chunkLength = 0; | 272 Vector<SVGTextFragment>& fragments = (*boxIter)->textFragments(); |
| 222 chunkCharacters = 0; | |
| 223 chunk.calculateLength(chunkLength, chunkCharacters); | |
| 224 } | |
| 225 | |
| 226 float textAnchorShift = chunk.calculateTextAnchorShift(chunkLength); | |
| 227 for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { | |
| 228 Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments() ; | |
| 229 if (fragments.isEmpty()) | 273 if (fragments.isEmpty()) |
| 230 continue; | 274 continue; |
| 231 processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments); | 275 processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments); |
| 232 } | 276 } |
| 233 } | 277 } |
| 234 | 278 |
| 235 void SVGTextChunkBuilder::processTextLengthSpacingCorrection(bool isVerticalText , float textLengthShift, Vector<SVGTextFragment>& fragments, unsigned& atCharact er) | 279 void SVGTextChunkBuilder::processTextLengthSpacingCorrection(bool isVerticalText , float textLengthShift, Vector<SVGTextFragment>& fragments, unsigned& atCharact er) |
| 236 { | 280 { |
| 237 unsigned fragmentCount = fragments.size(); | 281 unsigned fragmentCount = fragments.size(); |
| 238 for (unsigned i = 0; i < fragmentCount; ++i) { | 282 for (unsigned i = 0; i < fragmentCount; ++i) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 continue; | 315 continue; |
| 272 | 316 |
| 273 for (SVGTextFragment& fragment : textBox->textFragments()) { | 317 for (SVGTextFragment& fragment : textBox->textFragments()) { |
| 274 ASSERT(fragment.lengthAdjustTransform.isIdentity()); | 318 ASSERT(fragment.lengthAdjustTransform.isIdentity()); |
| 275 fragment.lengthAdjustTransform = textBoxTransformation; | 319 fragment.lengthAdjustTransform = textBoxTransformation; |
| 276 } | 320 } |
| 277 } | 321 } |
| 278 } | 322 } |
| 279 | 323 |
| 280 } | 324 } |
| OLD | NEW |