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