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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 const SVGInlineTextBox* textBox; | 47 const SVGInlineTextBox* textBox; |
48 }; | 48 }; |
49 | 49 |
50 static inline InlineFlowBox* flowBoxForLayoutObject( | 50 static inline InlineFlowBox* flowBoxForLayoutObject( |
51 LayoutObject* layoutObject) { | 51 LayoutObject* layoutObject) { |
52 if (!layoutObject) | 52 if (!layoutObject) |
53 return nullptr; | 53 return nullptr; |
54 | 54 |
55 if (layoutObject->isLayoutBlock()) { | 55 if (layoutObject->isLayoutBlock()) { |
56 // If we're given a block element, it has to be a LayoutSVGText. | 56 // If we're given a block element, it has to be a LayoutSVGText. |
57 ASSERT(layoutObject->isSVGText()); | 57 DCHECK(layoutObject->isSVGText()); |
58 LayoutBlockFlow* layoutBlockFlow = toLayoutBlockFlow(layoutObject); | 58 LayoutBlockFlow* layoutBlockFlow = toLayoutBlockFlow(layoutObject); |
59 | 59 |
60 // LayoutSVGText only ever contains a single line box. | 60 // LayoutSVGText only ever contains a single line box. |
61 InlineFlowBox* flowBox = layoutBlockFlow->firstLineBox(); | 61 InlineFlowBox* flowBox = layoutBlockFlow->firstLineBox(); |
62 ASSERT(flowBox == layoutBlockFlow->lastLineBox()); | 62 DCHECK_EQ(flowBox, layoutBlockFlow->lastLineBox()); |
63 return flowBox; | 63 return flowBox; |
64 } | 64 } |
65 | 65 |
66 if (layoutObject->isLayoutInline()) { | 66 if (layoutObject->isLayoutInline()) { |
67 // We're given a LayoutSVGInline or objects that derive from it | 67 // We're given a LayoutSVGInline or objects that derive from it |
68 // (LayoutSVGTSpan / LayoutSVGTextPath) | 68 // (LayoutSVGTSpan / LayoutSVGTextPath) |
69 LayoutInline* layoutInline = toLayoutInline(layoutObject); | 69 LayoutInline* layoutInline = toLayoutInline(layoutObject); |
70 | 70 |
71 // LayoutSVGInline only ever contains a single line box. | 71 // LayoutSVGInline only ever contains a single line box. |
72 InlineFlowBox* flowBox = layoutInline->firstLineBox(); | 72 InlineFlowBox* flowBox = layoutInline->firstLineBox(); |
73 ASSERT(flowBox == layoutInline->lastLineBox()); | 73 DCHECK_EQ(flowBox, layoutInline->lastLineBox()); |
74 return flowBox; | 74 return flowBox; |
75 } | 75 } |
76 | 76 |
77 NOTREACHED(); | 77 NOTREACHED(); |
78 return nullptr; | 78 return nullptr; |
79 } | 79 } |
80 | 80 |
81 static void collectTextBoxesInFlowBox(InlineFlowBox* flowBox, | 81 static void collectTextBoxesInFlowBox(InlineFlowBox* flowBox, |
82 Vector<SVGInlineTextBox*>& textBoxes) { | 82 Vector<SVGInlineTextBox*>& textBoxes) { |
83 if (!flowBox) | 83 if (!flowBox) |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 // Walk the layout tree in pre-order, starting at the specified root, and | 155 // Walk the layout tree in pre-order, starting at the specified root, and |
156 // run the query for each text node. | 156 // run the query for each text node. |
157 Vector<SVGInlineTextBox*> textBoxes; | 157 Vector<SVGInlineTextBox*> textBoxes; |
158 for (LayoutObject* layoutObject = queryRoot->slowFirstChild(); layoutObject; | 158 for (LayoutObject* layoutObject = queryRoot->slowFirstChild(); layoutObject; |
159 layoutObject = layoutObject->nextInPreOrder(queryRoot)) { | 159 layoutObject = layoutObject->nextInPreOrder(queryRoot)) { |
160 if (!layoutObject->isSVGInlineText()) | 160 if (!layoutObject->isSVGInlineText()) |
161 continue; | 161 continue; |
162 | 162 |
163 LineLayoutSVGInlineText textLineLayout = | 163 LineLayoutSVGInlineText textLineLayout = |
164 LineLayoutSVGInlineText(toLayoutSVGInlineText(layoutObject)); | 164 LineLayoutSVGInlineText(toLayoutSVGInlineText(layoutObject)); |
165 ASSERT(textLineLayout.style()); | 165 DCHECK(textLineLayout.style()); |
166 | 166 |
167 // TODO(fs): Allow filtering the search earlier, since we should be | 167 // TODO(fs): Allow filtering the search earlier, since we should be |
168 // able to trivially reject (prune) at least some of the queries. | 168 // able to trivially reject (prune) at least some of the queries. |
169 collectTextBoxesInLogicalOrder(textLineLayout, textBoxes); | 169 collectTextBoxesInLogicalOrder(textLineLayout, textBoxes); |
170 | 170 |
171 for (const SVGInlineTextBox* textBox : textBoxes) { | 171 for (const SVGInlineTextBox* textBox : textBoxes) { |
172 if (queryTextBox(queryData, textBox, fragmentCallback)) | 172 if (queryTextBox(queryData, textBox, fragmentCallback)) |
173 return; | 173 return; |
174 queryData->currentOffset += textBox->len(); | 174 queryData->currentOffset += textBox->len(); |
175 } | 175 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 // |startInFragment|. | 236 // |startInFragment|. |
237 MetricsList::const_iterator metrics = | 237 MetricsList::const_iterator metrics = |
238 metricsList.begin() + fragment.metricsListOffset; | 238 metricsList.begin() + fragment.metricsListOffset; |
239 unsigned fragmentOffset = 0; | 239 unsigned fragmentOffset = 0; |
240 while (fragmentOffset < fragment.length) { | 240 while (fragmentOffset < fragment.length) { |
241 fragmentOffset += metrics->length(); | 241 fragmentOffset += metrics->length(); |
242 if (startInFragment < fragmentOffset) | 242 if (startInFragment < fragmentOffset) |
243 break; | 243 break; |
244 ++metrics; | 244 ++metrics; |
245 } | 245 } |
246 ASSERT(metrics <= metricsList.end()); | 246 DCHECK_LE(metrics, metricsList.end()); |
247 return metrics; | 247 return metrics; |
248 } | 248 } |
249 | 249 |
250 static float calculateGlyphRange(const QueryData* queryData, | 250 static float calculateGlyphRange(const QueryData* queryData, |
251 const SVGTextFragment& fragment, | 251 const SVGTextFragment& fragment, |
252 unsigned start, | 252 unsigned start, |
253 unsigned end) { | 253 unsigned end) { |
254 const MetricsList& metricsList = queryData->textLineLayout.metricsList(); | 254 const MetricsList& metricsList = queryData->textLineLayout.metricsList(); |
255 auto metrics = findMetricsForCharacter(metricsList, fragment, start); | 255 auto metrics = findMetricsForCharacter(metricsList, fragment, start); |
256 auto endMetrics = findMetricsForCharacter(metricsList, fragment, end); | 256 auto endMetrics = findMetricsForCharacter(metricsList, fragment, end); |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 glyphExtents.move(-glyphExtents.width(), 0); | 458 glyphExtents.move(-glyphExtents.width(), 0); |
459 } | 459 } |
460 return glyphExtents; | 460 return glyphExtents; |
461 } | 461 } |
462 | 462 |
463 static inline FloatRect calculateGlyphBoundaries( | 463 static inline FloatRect calculateGlyphBoundaries( |
464 const QueryData* queryData, | 464 const QueryData* queryData, |
465 const SVGTextFragment& fragment, | 465 const SVGTextFragment& fragment, |
466 int startPosition) { | 466 int startPosition) { |
467 const float scalingFactor = queryData->textLineLayout.scalingFactor(); | 467 const float scalingFactor = queryData->textLineLayout.scalingFactor(); |
468 ASSERT(scalingFactor); | 468 DCHECK(scalingFactor); |
469 const SimpleFontData* fontData = | 469 const SimpleFontData* fontData = |
470 queryData->textLineLayout.scaledFont().primaryFont(); | 470 queryData->textLineLayout.scaledFont().primaryFont(); |
471 DCHECK(fontData); | 471 DCHECK(fontData); |
472 if (!fontData) | 472 if (!fontData) |
473 return FloatRect(); | 473 return FloatRect(); |
474 | 474 |
475 const float baseline = | 475 const float baseline = |
476 fontData->getFontMetrics().floatAscent() / scalingFactor; | 476 fontData->getFontMetrics().floatAscent() / scalingFactor; |
477 float glyphOffsetInDirection = | 477 float glyphOffsetInDirection = |
478 calculateGlyphRange(queryData, fragment, 0, startPosition); | 478 calculateGlyphRange(queryData, fragment, 0, startPosition); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 LineLayoutItem hitLayoutItem; | 524 LineLayoutItem hitLayoutItem; |
525 int offsetInTextNode; | 525 int offsetInTextNode; |
526 }; | 526 }; |
527 | 527 |
528 int CharacterNumberAtPositionData::characterNumberWithin( | 528 int CharacterNumberAtPositionData::characterNumberWithin( |
529 const LayoutObject* queryRoot) const { | 529 const LayoutObject* queryRoot) const { |
530 // http://www.w3.org/TR/SVG/single-page.html#text-__svg__SVGTextContentElement
__getCharNumAtPosition | 530 // http://www.w3.org/TR/SVG/single-page.html#text-__svg__SVGTextContentElement
__getCharNumAtPosition |
531 // "If no such character exists, a value of -1 is returned." | 531 // "If no such character exists, a value of -1 is returned." |
532 if (!hitLayoutItem) | 532 if (!hitLayoutItem) |
533 return -1; | 533 return -1; |
534 ASSERT(queryRoot); | 534 DCHECK(queryRoot); |
535 int characterNumber = offsetInTextNode; | 535 int characterNumber = offsetInTextNode; |
536 | 536 |
537 // Accumulate the lengths of all the text nodes preceding the target layout | 537 // Accumulate the lengths of all the text nodes preceding the target layout |
538 // object within the queried root, to get the complete character number. | 538 // object within the queried root, to get the complete character number. |
539 for (LineLayoutItem layoutItem = hitLayoutItem.previousInPreOrder(queryRoot); | 539 for (LineLayoutItem layoutItem = hitLayoutItem.previousInPreOrder(queryRoot); |
540 layoutItem; layoutItem = layoutItem.previousInPreOrder(queryRoot)) { | 540 layoutItem; layoutItem = layoutItem.previousInPreOrder(queryRoot)) { |
541 if (!layoutItem.isSVGInlineText()) | 541 if (!layoutItem.isSVGInlineText()) |
542 continue; | 542 continue; |
543 characterNumber += LineLayoutSVGInlineText(layoutItem).resolvedTextLength(); | 543 characterNumber += LineLayoutSVGInlineText(layoutItem).resolvedTextLength(); |
544 } | 544 } |
545 return characterNumber; | 545 return characterNumber; |
546 } | 546 } |
547 | 547 |
548 static unsigned logicalOffsetInTextNode(LineLayoutSVGInlineText textLineLayout, | 548 static unsigned logicalOffsetInTextNode(LineLayoutSVGInlineText textLineLayout, |
549 const SVGInlineTextBox* startTextBox, | 549 const SVGInlineTextBox* startTextBox, |
550 unsigned fragmentOffset) { | 550 unsigned fragmentOffset) { |
551 Vector<SVGInlineTextBox*> textBoxes; | 551 Vector<SVGInlineTextBox*> textBoxes; |
552 collectTextBoxesInLogicalOrder(textLineLayout, textBoxes); | 552 collectTextBoxesInLogicalOrder(textLineLayout, textBoxes); |
553 | 553 |
554 ASSERT(startTextBox); | 554 DCHECK(startTextBox); |
555 size_t index = textBoxes.find(startTextBox); | 555 size_t index = textBoxes.find(startTextBox); |
556 ASSERT(index != kNotFound); | 556 DCHECK_NE(index, kNotFound); |
557 | 557 |
558 unsigned offset = fragmentOffset; | 558 unsigned offset = fragmentOffset; |
559 while (index) { | 559 while (index) { |
560 --index; | 560 --index; |
561 offset += textBoxes[index]->len(); | 561 offset += textBoxes[index]->len(); |
562 } | 562 } |
563 return offset; | 563 return offset; |
564 } | 564 } |
565 | 565 |
566 static bool characterNumberAtPositionCallback(QueryData* queryData, | 566 static bool characterNumberAtPositionCallback(QueryData* queryData, |
567 const SVGTextFragment& fragment) { | 567 const SVGTextFragment& fragment) { |
568 CharacterNumberAtPositionData* data = | 568 CharacterNumberAtPositionData* data = |
569 static_cast<CharacterNumberAtPositionData*>(queryData); | 569 static_cast<CharacterNumberAtPositionData*>(queryData); |
570 | 570 |
571 const float scalingFactor = data->textLineLayout.scalingFactor(); | 571 const float scalingFactor = data->textLineLayout.scalingFactor(); |
572 ASSERT(scalingFactor); | 572 DCHECK(scalingFactor); |
573 | 573 |
574 const SimpleFontData* fontData = | 574 const SimpleFontData* fontData = |
575 data->textLineLayout.scaledFont().primaryFont(); | 575 data->textLineLayout.scaledFont().primaryFont(); |
576 DCHECK(fontData); | 576 DCHECK(fontData); |
577 if (!fontData) | 577 if (!fontData) |
578 return false; | 578 return false; |
579 | 579 |
580 const float baseline = | 580 const float baseline = |
581 fontData->getFontMetrics().floatAscent() / scalingFactor; | 581 fontData->getFontMetrics().floatAscent() / scalingFactor; |
582 | 582 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
617 } | 617 } |
618 | 618 |
619 int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const { | 619 int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const { |
620 CharacterNumberAtPositionData data(position); | 620 CharacterNumberAtPositionData data(position); |
621 spatialQuery(m_queryRootLayoutObject, &data, | 621 spatialQuery(m_queryRootLayoutObject, &data, |
622 characterNumberAtPositionCallback); | 622 characterNumberAtPositionCallback); |
623 return data.characterNumberWithin(m_queryRootLayoutObject); | 623 return data.characterNumberWithin(m_queryRootLayoutObject); |
624 } | 624 } |
625 | 625 |
626 } // namespace blink | 626 } // namespace blink |
OLD | NEW |