OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. | 2 * Copyright (C) Research In Motion Limited 2010-2012. 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 15 matching lines...) Expand all Loading... |
26 #include "core/layout/svg/SVGTextLayoutEngineBaseline.h" | 26 #include "core/layout/svg/SVGTextLayoutEngineBaseline.h" |
27 #include "core/layout/svg/SVGTextLayoutEngineSpacing.h" | 27 #include "core/layout/svg/SVGTextLayoutEngineSpacing.h" |
28 #include "core/layout/svg/line/SVGInlineFlowBox.h" | 28 #include "core/layout/svg/line/SVGInlineFlowBox.h" |
29 #include "core/layout/svg/line/SVGInlineTextBox.h" | 29 #include "core/layout/svg/line/SVGInlineTextBox.h" |
30 #include "core/svg/SVGElement.h" | 30 #include "core/svg/SVGElement.h" |
31 #include "core/svg/SVGLengthContext.h" | 31 #include "core/svg/SVGLengthContext.h" |
32 #include "core/svg/SVGTextContentElement.h" | 32 #include "core/svg/SVGTextContentElement.h" |
33 | 33 |
34 namespace blink { | 34 namespace blink { |
35 | 35 |
36 SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes*>& layou
tAttributes) | 36 SVGTextLayoutEngine::SVGTextLayoutEngine(const Vector<LayoutSVGInlineText*>& des
cendantTextNodes) |
37 : m_layoutAttributes(layoutAttributes) | 37 : m_descendantTextNodes(descendantTextNodes) |
38 , m_layoutAttributesPosition(0) | 38 , m_currentLogicalTextNodeIndex(0) |
39 , m_logicalCharacterOffset(0) | 39 , m_logicalCharacterOffset(0) |
40 , m_logicalMetricsListOffset(0) | 40 , m_logicalMetricsListOffset(0) |
41 , m_isVerticalText(false) | 41 , m_isVerticalText(false) |
42 , m_inPathLayout(false) | 42 , m_inPathLayout(false) |
43 , m_textLengthSpacingInEffect(false) | 43 , m_textLengthSpacingInEffect(false) |
44 , m_textPath(nullptr) | 44 , m_textPath(nullptr) |
45 , m_textPathCurrentOffset(0) | 45 , m_textPathCurrentOffset(0) |
46 , m_textPathDisplacement(0) | 46 , m_textPathDisplacement(0) |
47 , m_textPathSpacing(0) | 47 , m_textPathSpacing(0) |
48 , m_textPathScaling(1) | 48 , m_textPathScaling(1) |
49 { | 49 { |
50 ASSERT(!m_layoutAttributes.isEmpty()); | 50 ASSERT(!m_descendantTextNodes.isEmpty()); |
51 } | 51 } |
52 | 52 |
53 SVGTextLayoutEngine::~SVGTextLayoutEngine() = default; | 53 SVGTextLayoutEngine::~SVGTextLayoutEngine() = default; |
54 | 54 |
55 bool SVGTextLayoutEngine::setCurrentTextPosition(const SVGCharacterData& data) | 55 bool SVGTextLayoutEngine::setCurrentTextPosition(const SVGCharacterData& data) |
56 { | 56 { |
57 bool hasX = data.hasX(); | 57 bool hasX = data.hasX(); |
58 if (hasX) | 58 if (hasX) |
59 m_textPosition.setX(data.x); | 59 m_textPosition.setX(data.x); |
60 | 60 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 computeCurrentFragmentMetrics(textBox); | 149 computeCurrentFragmentMetrics(textBox); |
150 | 150 |
151 textBox->textFragments().append(m_currentTextFragment); | 151 textBox->textFragments().append(m_currentTextFragment); |
152 m_currentTextFragment = SVGTextFragment(); | 152 m_currentTextFragment = SVGTextFragment(); |
153 } | 153 } |
154 | 154 |
155 void SVGTextLayoutEngine::beginTextPathLayout(SVGInlineFlowBox* flowBox) | 155 void SVGTextLayoutEngine::beginTextPathLayout(SVGInlineFlowBox* flowBox) |
156 { | 156 { |
157 // Build text chunks for all <textPath> children, using the line layout algo
rithm. | 157 // Build text chunks for all <textPath> children, using the line layout algo
rithm. |
158 // This is needeed as text-anchor is just an additional startOffset for text
paths. | 158 // This is needeed as text-anchor is just an additional startOffset for text
paths. |
159 SVGTextLayoutEngine lineLayout(m_layoutAttributes); | 159 SVGTextLayoutEngine lineLayout(m_descendantTextNodes); |
160 lineLayout.m_textLengthSpacingInEffect = m_textLengthSpacingInEffect; | 160 lineLayout.m_textLengthSpacingInEffect = m_textLengthSpacingInEffect; |
161 lineLayout.layoutCharactersInTextBoxes(flowBox); | 161 lineLayout.layoutCharactersInTextBoxes(flowBox); |
162 | 162 |
163 m_inPathLayout = true; | 163 m_inPathLayout = true; |
164 LineLayoutSVGTextPath textPath = LineLayoutSVGTextPath(flowBox->getLineLayou
tItem()); | 164 LineLayoutSVGTextPath textPath = LineLayoutSVGTextPath(flowBox->getLineLayou
tItem()); |
165 | 165 |
166 m_textPath = textPath.layoutPath(); | 166 m_textPath = textPath.layoutPath(); |
167 if (!m_textPath) | 167 if (!m_textPath) |
168 return; | 168 return; |
169 m_textPathStartOffset = textPath.calculateStartOffset(m_textPath->length()); | 169 m_textPathStartOffset = textPath.calculateStartOffset(m_textPath->length()); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 m_visualMetricsIterator = SVGInlineTextMetricsIterator(); | 269 m_visualMetricsIterator = SVGInlineTextMetricsIterator(); |
270 | 270 |
271 // After all text fragments are stored in their correpsonding SVGInlineTextB
oxes, we can layout individual text chunks. | 271 // After all text fragments are stored in their correpsonding SVGInlineTextB
oxes, we can layout individual text chunks. |
272 // Chunk layouting is only performed for line layout boxes, not for path lay
out, where it has already been done. | 272 // Chunk layouting is only performed for line layout boxes, not for path lay
out, where it has already been done. |
273 SVGTextChunkBuilder chunkLayoutBuilder; | 273 SVGTextChunkBuilder chunkLayoutBuilder; |
274 chunkLayoutBuilder.processTextChunks(m_lineLayoutBoxes); | 274 chunkLayoutBuilder.processTextChunks(m_lineLayoutBoxes); |
275 | 275 |
276 m_lineLayoutBoxes.clear(); | 276 m_lineLayoutBoxes.clear(); |
277 } | 277 } |
278 | 278 |
279 const SVGTextLayoutAttributes* SVGTextLayoutEngine::nextLogicalAttributes() | 279 const LayoutSVGInlineText* SVGTextLayoutEngine::nextLogicalTextNode() |
280 { | 280 { |
281 ASSERT(m_layoutAttributesPosition < m_layoutAttributes.size()); | 281 ASSERT(m_currentLogicalTextNodeIndex < m_descendantTextNodes.size()); |
282 ++m_layoutAttributesPosition; | 282 ++m_currentLogicalTextNodeIndex; |
283 if (m_layoutAttributesPosition == m_layoutAttributes.size()) | 283 if (m_currentLogicalTextNodeIndex == m_descendantTextNodes.size()) |
284 return nullptr; | 284 return nullptr; |
285 | 285 |
286 m_logicalMetricsListOffset = 0; | 286 m_logicalMetricsListOffset = 0; |
287 m_logicalCharacterOffset = 0; | 287 m_logicalCharacterOffset = 0; |
288 return m_layoutAttributes[m_layoutAttributesPosition]; | 288 return m_descendantTextNodes[m_currentLogicalTextNodeIndex]; |
289 } | 289 } |
290 | 290 |
291 const SVGTextLayoutAttributes* SVGTextLayoutEngine::currentLogicalCharacterMetri
cs(SVGTextMetrics& logicalMetrics) | 291 const LayoutSVGInlineText* SVGTextLayoutEngine::currentLogicalCharacterMetrics(S
VGTextMetrics& logicalMetrics) |
292 { | 292 { |
293 // If we're consumed all layout attributes, there can be no more metrics. | 293 // If we're consumed all text nodes, there can be no more metrics. |
294 if (m_layoutAttributesPosition == m_layoutAttributes.size()) | 294 if (m_currentLogicalTextNodeIndex == m_descendantTextNodes.size()) |
295 return nullptr; | 295 return nullptr; |
296 | 296 |
297 const SVGTextLayoutAttributes* logicalAttributes = m_layoutAttributes[m_layo
utAttributesPosition]; | 297 const LayoutSVGInlineText* logicalTextNode = m_descendantTextNodes[m_current
LogicalTextNodeIndex]; |
298 // If we reached the end of the text node associated with the current set | 298 // If we reached the end of the text node associated with the current set |
299 // of layout attributes, try to move to the next text node/set of layout | 299 // of layout attributes, try to move to the next text node/set of layout |
300 // attributes. | 300 // attributes. |
301 ASSERT(m_logicalCharacterOffset <= logicalAttributes->context()->textLength(
)); | 301 ASSERT(m_logicalCharacterOffset <= logicalTextNode->textLength()); |
302 if (m_logicalCharacterOffset == logicalAttributes->context()->textLength())
{ | 302 if (m_logicalCharacterOffset == logicalTextNode->textLength()) { |
303 logicalAttributes = nextLogicalAttributes(); | 303 logicalTextNode = nextLogicalTextNode(); |
304 if (!logicalAttributes) | 304 if (!logicalTextNode) |
305 return nullptr; | 305 return nullptr; |
306 } | 306 } |
307 | 307 |
308 // We have set of layout attributes. Find the first non-collapsed text | 308 // We have set of layout attributes. Find the first non-collapsed text |
309 // metrics cell. | 309 // metrics cell. |
310 const Vector<SVGTextMetrics>* metricsList = &logicalAttributes->context()->m
etricsList(); | 310 const Vector<SVGTextMetrics>* metricsList = &logicalTextNode->metricsList(); |
311 unsigned metricsListSize = metricsList->size(); | 311 unsigned metricsListSize = metricsList->size(); |
312 while (true) { | 312 while (true) { |
313 // If we run out of metrics, move to the next set of layout attributes. | 313 // If we run out of metrics, move to the next set of layout attributes. |
314 if (m_logicalMetricsListOffset == metricsListSize) { | 314 if (m_logicalMetricsListOffset == metricsListSize) { |
315 logicalAttributes = nextLogicalAttributes(); | 315 logicalTextNode = nextLogicalTextNode(); |
316 if (!logicalAttributes) | 316 if (!logicalTextNode) |
317 return nullptr; | 317 return nullptr; |
318 | 318 |
319 metricsList = &logicalAttributes->context()->metricsList(); | 319 metricsList = &logicalTextNode->metricsList(); |
320 metricsListSize = metricsList->size(); | 320 metricsListSize = metricsList->size(); |
321 continue; | 321 continue; |
322 } | 322 } |
323 | 323 |
324 ASSERT(metricsListSize); | 324 ASSERT(metricsListSize); |
325 ASSERT(m_logicalMetricsListOffset < metricsListSize); | 325 ASSERT(m_logicalMetricsListOffset < metricsListSize); |
326 logicalMetrics = metricsList->at(m_logicalMetricsListOffset); | 326 logicalMetrics = metricsList->at(m_logicalMetricsListOffset); |
327 if (logicalMetrics.isEmpty() || (!logicalMetrics.width() && !logicalMetr
ics.height())) { | 327 if (logicalMetrics.isEmpty() || (!logicalMetrics.width() && !logicalMetr
ics.height())) { |
328 advanceToNextLogicalCharacter(logicalMetrics); | 328 advanceToNextLogicalCharacter(logicalMetrics); |
329 continue; | 329 continue; |
330 } | 330 } |
331 | 331 |
332 // Stop if we found the next valid logical text metrics object. | 332 // Stop if we found the next valid logical text metrics object. |
333 return logicalAttributes; | 333 return logicalTextNode; |
334 } | 334 } |
335 | 335 |
336 ASSERT_NOT_REACHED(); | 336 ASSERT_NOT_REACHED(); |
337 return nullptr; | 337 return nullptr; |
338 } | 338 } |
339 | 339 |
340 void SVGTextLayoutEngine::advanceToNextLogicalCharacter(const SVGTextMetrics& lo
gicalMetrics) | 340 void SVGTextLayoutEngine::advanceToNextLogicalCharacter(const SVGTextMetrics& lo
gicalMetrics) |
341 { | 341 { |
342 ++m_logicalMetricsListOffset; | 342 ++m_logicalMetricsListOffset; |
343 m_logicalCharacterOffset += logicalMetrics.length(); | 343 m_logicalCharacterOffset += logicalMetrics.length(); |
(...skipping 28 matching lines...) Expand all Loading... |
372 // Main layout algorithm. | 372 // Main layout algorithm. |
373 const unsigned boxEndOffset = textBox->start() + textBox->len(); | 373 const unsigned boxEndOffset = textBox->start() + textBox->len(); |
374 while (!m_visualMetricsIterator.isAtEnd() && m_visualMetricsIterator.charact
erOffset() < boxEndOffset) { | 374 while (!m_visualMetricsIterator.isAtEnd() && m_visualMetricsIterator.charact
erOffset() < boxEndOffset) { |
375 const SVGTextMetrics& visualMetrics = m_visualMetricsIterator.metrics(); | 375 const SVGTextMetrics& visualMetrics = m_visualMetricsIterator.metrics(); |
376 if (visualMetrics.isEmpty()) { | 376 if (visualMetrics.isEmpty()) { |
377 m_visualMetricsIterator.next(); | 377 m_visualMetricsIterator.next(); |
378 continue; | 378 continue; |
379 } | 379 } |
380 | 380 |
381 SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics); | 381 SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics); |
382 const SVGTextLayoutAttributes* logicalAttributes = currentLogicalCharact
erMetrics(logicalMetrics); | 382 const LayoutSVGInlineText* logicalTextNode = currentLogicalCharacterMetr
ics(logicalMetrics); |
383 if (!logicalAttributes) | 383 if (!logicalTextNode) |
384 break; | 384 break; |
385 | 385 |
386 const SVGCharacterDataMap& characterDataMap = logicalAttributes->charact
erDataMap(); | 386 const SVGCharacterData data = logicalTextNode->characterDataMap().get(m_
logicalCharacterOffset + 1); |
387 SVGCharacterData data; | |
388 SVGCharacterDataMap::const_iterator it = characterDataMap.find(m_logical
CharacterOffset + 1); | |
389 if (it != characterDataMap.end()) | |
390 data = it->value; | |
391 | 387 |
392 // TODO(fs): Use the return value to eliminate the additional | 388 // TODO(fs): Use the return value to eliminate the additional |
393 // hash-lookup below when determining if this text box should be tagged | 389 // hash-lookup below when determining if this text box should be tagged |
394 // as starting a new text chunk. | 390 // as starting a new text chunk. |
395 setCurrentTextPosition(data); | 391 setCurrentTextPosition(data); |
396 | 392 |
397 // When we've advanced to the box start offset, determine using the orig
inal x/y values, | 393 // When we've advanced to the box start offset, determine using the orig
inal x/y values, |
398 // whether this character starts a new text chunk, before doing any furt
her processing. | 394 // whether this character starts a new text chunk, before doing any furt
her processing. |
399 if (m_visualMetricsIterator.characterOffset() == textBox->start()) | 395 if (m_visualMetricsIterator.characterOffset() == textBox->start()) |
400 textBox->setStartsNewTextChunk(logicalAttributes->context()->charact
erStartsNewTextChunk(m_logicalCharacterOffset)); | 396 textBox->setStartsNewTextChunk(logicalTextNode->characterStartsNewTe
xtChunk(m_logicalCharacterOffset)); |
401 | 397 |
402 bool hasRelativePosition = applyRelativePositionAdjustmentsIfNeeded(data
); | 398 bool hasRelativePosition = applyRelativePositionAdjustmentsIfNeeded(data
); |
403 | 399 |
404 // Determine the orientation of the current glyph. | 400 // Determine the orientation of the current glyph. |
405 // Font::width() calculates the resolved FontOrientation for each charac
ter, | 401 // Font::width() calculates the resolved FontOrientation for each charac
ter, |
406 // but that value is not exposed today to avoid the API complexity. | 402 // but that value is not exposed today to avoid the API complexity. |
407 UChar32 currentCharacter = textLineLayout.codepointAt(m_visualMetricsIte
rator.characterOffset()); | 403 UChar32 currentCharacter = textLineLayout.codepointAt(m_visualMetricsIte
rator.characterOffset()); |
408 FontOrientation fontOrientation = font.getFontDescription().orientation(
); | 404 FontOrientation fontOrientation = font.getFontDescription().orientation(
); |
409 fontOrientation = adjustOrientationForCharacterInMixedVertical(fontOrien
tation, currentCharacter); | 405 fontOrientation = adjustOrientationForCharacterInMixedVertical(fontOrien
tation, currentCharacter); |
410 | 406 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
510 } | 506 } |
511 | 507 |
512 if (!didStartTextFragment) | 508 if (!didStartTextFragment) |
513 return; | 509 return; |
514 | 510 |
515 // Close last open fragment, if needed. | 511 // Close last open fragment, if needed. |
516 recordTextFragment(textBox); | 512 recordTextFragment(textBox); |
517 } | 513 } |
518 | 514 |
519 } // namespace blink | 515 } // namespace blink |
OLD | NEW |