Changeset 105057 in webkit


Ignore:
Timestamp:
Jan 16, 2012 5:08:29 AM (12 years ago)
Author:
Nikolas Zimmermann
Message:

Large SVG text layout performance regression in r81168
https://bugs.webkit.org/show_bug.cgi?id=65711

Reviewed by Zoltan Herczeg.

Change the way we store x/y/dx/dy/rotate values for a <text> element and its ancestors.

SVGTextLayoutAttributesBuilder used to hold a Vector<float> for x/y/dx/dy/rotate, each as big
as the whole text subtree length. For each character, that has an absolute position, or rotation
the value was stored in this list. For all other characters a special empty value marker was stored.

This is highly inefficient, and is now replaced with a HashMap<unsigned, SVGCharacterData> where
SVGCharacterData is a struct, holding float x/y/dx/dy/rotate. The code is now optimized for the
common case, where only a few characters actually specify such values, eg:
<text x="50" y="90">looooong text<tspan x="50" y="30">abc</tspan></text>.

NOTE: There are still some inefficiencies in this patch (especially the copying of SVGTextLayoutAttributes).
To keep the patch size smaller, I decided to fix this in another patch, and only fix the memory issue with this patch.

This reduces the memory consumption from 35MB to 10MB on the attached testcase in bug 65711.

Doesn't affect any test, yet. A follow-up commit will enable the usage of the simple code path, using WidthIterator,
in SVGTextMetricsBuilder, which will result in several layout test changes, because of geometry changes.

  • rendering/svg/RenderSVGInlineText.cpp:

(WebCore::RenderSVGInlineText::RenderSVGInlineText):
(WebCore::RenderSVGInlineText::characterStartsNewTextChunk):

  • rendering/svg/RenderSVGInlineText.h:

(WebCore::RenderSVGInlineText::layoutAttributes):

  • rendering/svg/RenderSVGText.cpp:

(WebCore::RenderSVGText::layout):
(WebCore::recursiveCollectLayoutAttributes):
(WebCore::RenderSVGText::rebuildLayoutAttributes):

  • rendering/svg/RenderSVGText.h:
  • rendering/svg/SVGRootInlineBox.cpp:

(WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation):
(WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes):
(WebCore::SVGRootInlineBox::closestLeafChildForPosition):
(WebCore::swapItemsInLayoutAttributes):
(WebCore::findFirstAndLastAttributesInVector):
(WebCore::reverseInlineBoxRangeAndValueListsIfNeeded):

  • rendering/svg/SVGTextLayoutAttributes.cpp:

(WebCore::SVGTextLayoutAttributes::clear):
(WebCore::dumpSVGCharacterDataMapValue):
(WebCore::SVGTextLayoutAttributes::dump):

  • rendering/svg/SVGTextLayoutAttributes.h:

(WebCore::SVGTextLayoutAttributes::characterDataMap):

  • rendering/svg/SVGTextLayoutAttributesBuilder.cpp:

(WebCore::SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder):
(WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer):
(WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForWholeTree):
(WebCore::SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer):
(WebCore::SVGTextLayoutAttributesBuilder::rebuildMetricsForWholeTree):
(WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesIfNeeded):
(WebCore::processRenderSVGInlineText):
(WebCore::SVGTextLayoutAttributesBuilder::collectTextPositioningElements):
(WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributes):
(WebCore::updateCharacterData):
(WebCore::SVGTextLayoutAttributesBuilder::fillCharacterDataMap):

  • rendering/svg/SVGTextLayoutAttributesBuilder.h:

(WebCore::SVGTextLayoutAttributesBuilder::clearTextPositioningElements):

  • rendering/svg/SVGTextLayoutEngine.cpp:

(WebCore::SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded):
(WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes):
(WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath):

  • rendering/svg/SVGTextLayoutEngine.h:

(WebCore::SVGTextLayoutEngine::layoutAttributes):

  • rendering/svg/SVGTextMetricsBuilder.cpp:

(WebCore::SVGTextMetricsBuilder::advance):
(WebCore::SVGTextMetricsBuilder::advanceComplexText):
(WebCore::SVGTextMetricsBuilder::measureTextRenderer):

  • rendering/svg/SVGTextQuery.cpp:

(WebCore::SVGTextQuery::modifyStartEndPositionsRespectingLigatures):

Location:
trunk/Source/WebCore
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r105056 r105057  
     12012-01-16  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Large SVG text layout performance regression in r81168
     4        https://bugs.webkit.org/show_bug.cgi?id=65711
     5
     6        Reviewed by Zoltan Herczeg.
     7
     8        Change the way we store x/y/dx/dy/rotate values for a <text> element and its ancestors.
     9
     10        SVGTextLayoutAttributesBuilder used to hold a Vector<float> for x/y/dx/dy/rotate, each as big
     11        as the whole text subtree length. For each character, that has an absolute position, or rotation
     12        the value was stored in this list. For all other characters a special empty value marker was stored.
     13
     14        This is highly inefficient, and is now replaced with a HashMap<unsigned, SVGCharacterData> where
     15        SVGCharacterData is a struct, holding float x/y/dx/dy/rotate. The code is now optimized for the
     16        common case, where only a few characters actually specify such values, eg:
     17        <text x="50" y="90">looooong text<tspan x="50" y="30">abc</tspan></text>.
     18
     19        NOTE: There are still some inefficiencies in this patch (especially the copying of SVGTextLayoutAttributes).
     20        To keep the patch size smaller, I decided to fix this in another patch, and only fix the memory issue with this patch.
     21
     22        This reduces the memory consumption from 35MB to 10MB on the attached testcase in bug 65711.
     23
     24        Doesn't affect any test, yet. A follow-up commit will enable the usage of the simple code path, using WidthIterator,
     25        in SVGTextMetricsBuilder, which will result in several layout test changes, because of geometry changes.
     26
     27        * rendering/svg/RenderSVGInlineText.cpp:
     28        (WebCore::RenderSVGInlineText::RenderSVGInlineText):
     29        (WebCore::RenderSVGInlineText::characterStartsNewTextChunk):
     30        * rendering/svg/RenderSVGInlineText.h:
     31        (WebCore::RenderSVGInlineText::layoutAttributes):
     32        * rendering/svg/RenderSVGText.cpp:
     33        (WebCore::RenderSVGText::layout):
     34        (WebCore::recursiveCollectLayoutAttributes):
     35        (WebCore::RenderSVGText::rebuildLayoutAttributes):
     36        * rendering/svg/RenderSVGText.h:
     37        * rendering/svg/SVGRootInlineBox.cpp:
     38        (WebCore::SVGRootInlineBox::computePerCharacterLayoutInformation):
     39        (WebCore::SVGRootInlineBox::layoutCharactersInTextBoxes):
     40        (WebCore::SVGRootInlineBox::closestLeafChildForPosition):
     41        (WebCore::swapItemsInLayoutAttributes):
     42        (WebCore::findFirstAndLastAttributesInVector):
     43        (WebCore::reverseInlineBoxRangeAndValueListsIfNeeded):
     44        * rendering/svg/SVGTextLayoutAttributes.cpp:
     45        (WebCore::SVGTextLayoutAttributes::clear):
     46        (WebCore::dumpSVGCharacterDataMapValue):
     47        (WebCore::SVGTextLayoutAttributes::dump):
     48        * rendering/svg/SVGTextLayoutAttributes.h:
     49        (WebCore::SVGTextLayoutAttributes::characterDataMap):
     50        * rendering/svg/SVGTextLayoutAttributesBuilder.cpp:
     51        (WebCore::SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder):
     52        (WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer):
     53        (WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesForWholeTree):
     54        (WebCore::SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer):
     55        (WebCore::SVGTextLayoutAttributesBuilder::rebuildMetricsForWholeTree):
     56        (WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributesIfNeeded):
     57        (WebCore::processRenderSVGInlineText):
     58        (WebCore::SVGTextLayoutAttributesBuilder::collectTextPositioningElements):
     59        (WebCore::SVGTextLayoutAttributesBuilder::buildLayoutAttributes):
     60        (WebCore::updateCharacterData):
     61        (WebCore::SVGTextLayoutAttributesBuilder::fillCharacterDataMap):
     62        * rendering/svg/SVGTextLayoutAttributesBuilder.h:
     63        (WebCore::SVGTextLayoutAttributesBuilder::clearTextPositioningElements):
     64        * rendering/svg/SVGTextLayoutEngine.cpp:
     65        (WebCore::SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded):
     66        (WebCore::SVGTextLayoutEngine::currentLogicalCharacterAttributes):
     67        (WebCore::SVGTextLayoutEngine::layoutTextOnLineOrPath):
     68        * rendering/svg/SVGTextLayoutEngine.h:
     69        (WebCore::SVGTextLayoutEngine::layoutAttributes):
     70        * rendering/svg/SVGTextMetricsBuilder.cpp:
     71        (WebCore::SVGTextMetricsBuilder::advance):
     72        (WebCore::SVGTextMetricsBuilder::advanceComplexText):
     73        (WebCore::SVGTextMetricsBuilder::measureTextRenderer):
     74        * rendering/svg/SVGTextQuery.cpp:
     75        (WebCore::SVGTextQuery::modifyStartEndPositionsRespectingLigatures):
     76
    1772012-01-15  Andreas Kling  <awesomekling@apple.com>
    278
  • trunk/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp

    r101342 r105057  
    6969    : RenderText(n, applySVGWhitespaceRules(string, false))
    7070    , m_scalingFactor(1)
     71    , m_layoutAttributes(this)
    7172{
    7273}
     
    141142bool RenderSVGInlineText::characterStartsNewTextChunk(int position) const
    142143{
    143     ASSERT(m_attributes.xValues().size() == textLength());
    144     ASSERT(m_attributes.yValues().size() == textLength());
    145144    ASSERT(position >= 0);
    146145    ASSERT(position < static_cast<int>(textLength()));
     
    150149        return true;
    151150
    152     int currentPosition = 0;
    153     unsigned size = m_attributes.textMetricsValues().size();
    154     for (unsigned i = 0; i < size; ++i) {
    155         const SVGTextMetrics& metrics = m_attributes.textMetricsValues().at(i);
    156 
    157         // We found the desired character.
    158         if (currentPosition == position) {
    159             return m_attributes.xValues().at(position) != SVGTextLayoutAttributes::emptyValue()
    160                 || m_attributes.yValues().at(position) != SVGTextLayoutAttributes::emptyValue();
    161         }
    162 
    163         currentPosition += metrics.length();
    164         if (currentPosition > position)
    165             break;
    166     }
    167 
    168     // The desired position is available in the x/y list, but not in the character data values list.
    169     // That means the previous character data described a single glyph, consisting of multiple unicode characters.
    170     // The consequence is that the desired character does not define a new absolute x/y position, even if present in the x/y test.
    171     // This code is tested by svg/W3C-SVG-1.1/text-text-06-t.svg (and described in detail, why this influences chunk detection).
    172     return false;
     151    const SVGCharacterDataMap::const_iterator it = m_layoutAttributes.characterDataMap().find(static_cast<unsigned>(position + 1));
     152    if (it == m_layoutAttributes.characterDataMap().end())
     153        return false;
     154
     155    return it->second.x != SVGTextLayoutAttributes::emptyValue() || it->second.y != SVGTextLayoutAttributes::emptyValue();
    173156}
    174157
  • trunk/Source/WebCore/rendering/svg/RenderSVGInlineText.h

    r101342 r105057  
    3636
    3737    bool characterStartsNewTextChunk(int position) const;
    38 
    39     SVGTextLayoutAttributes& layoutAttributes() { return m_attributes; }
    40     const SVGTextLayoutAttributes& layoutAttributes() const { return m_attributes; }
    41     void storeLayoutAttributes(const SVGTextLayoutAttributes& attributes) { m_attributes = attributes; }
     38    SVGTextLayoutAttributes& layoutAttributes() { return m_layoutAttributes; }
    4239
    4340    float scalingFactor() const { return m_scalingFactor; }
     
    6966    float m_scalingFactor;
    7067    Font m_scaledFont;
    71     SVGTextLayoutAttributes m_attributes;
     68    SVGTextLayoutAttributes m_layoutAttributes;
    7269};
    7370
  • trunk/Source/WebCore/rendering/svg/RenderSVGText.cpp

    r104683 r105057  
    142142    if (m_needsPositioningValuesUpdate) {
    143143        // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details).
    144         SVGTextLayoutAttributesBuilder layoutAttributesBuilder;
    145         layoutAttributesBuilder.buildLayoutAttributesForTextSubtree(this);
     144        m_layoutAttributesBuilder.buildLayoutAttributesForWholeTree(this);
    146145        m_needsReordering = true;
    147146        m_needsPositioningValuesUpdate = false;
     
    294293}
    295294
     295static inline void recursiveCollectLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& attributes)
     296{
     297    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
     298        if (child->isSVGInlineText()) {
     299            attributes.append(toRenderSVGInlineText(child)->layoutAttributes());
     300            continue;
     301        }
     302
     303        recursiveCollectLayoutAttributes(child, attributes);
     304    }
     305}
     306
     307void RenderSVGText::rebuildLayoutAttributes(bool performFullRebuild)
     308{
     309    // FIXME: For now we always rebuild the whole tree, as it used to be.
     310    performFullRebuild = true;
     311    if (performFullRebuild)
     312        m_layoutAttributes.clear();
     313
     314    if (m_layoutAttributes.isEmpty()) {
     315        recursiveCollectLayoutAttributes(this, m_layoutAttributes);
     316        if (m_layoutAttributes.isEmpty() || !performFullRebuild)
     317            return;
     318
     319        m_layoutAttributesBuilder.rebuildMetricsForWholeTree(this);
     320        return;
     321    }
     322
     323    /* FIXME: Enable this once we rebuild subtrees, instead of the full tree
     324    Vector<SVGTextLayoutAttributes*> affectedAttributes;
     325    rebuildLayoutAttributes(affectedAttributes);
     326    */
     327}
     328
    296329}
    297330
  • trunk/Source/WebCore/rendering/svg/RenderSVGText.h

    r104683 r105057  
    2727#include "AffineTransform.h"
    2828#include "RenderSVGBlock.h"
    29 #include "SVGTextLayoutAttributes.h"
     29#include "SVGTextLayoutAttributesBuilder.h"
    3030
    3131namespace WebCore {
     
    4949    Vector<SVGTextLayoutAttributes>& layoutAttributes() { return m_layoutAttributes; }
    5050    bool needsReordering() const { return m_needsReordering; }
     51
     52    void rebuildLayoutAttributes(bool performFullRebuild = false);
    5153
    5254private:
     
    8486    bool m_needsTransformUpdate : 1;
    8587    AffineTransform m_localTransform;
     88    SVGTextLayoutAttributesBuilder m_layoutAttributesBuilder;
    8689    Vector<SVGTextLayoutAttributes> m_layoutAttributes;
    8790};
  • trunk/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp

    r101342 r105057  
    7474void SVGRootInlineBox::computePerCharacterLayoutInformation()
    7575{
    76     RenderSVGText* parentBlock = toRenderSVGText(block());
    77     ASSERT(parentBlock);
    78 
    79     Vector<SVGTextLayoutAttributes>& attributes = parentBlock->layoutAttributes();
    80     if (attributes.isEmpty())
     76    RenderSVGText* textRoot = toRenderSVGText(block());
     77    ASSERT(textRoot);
     78
     79    textRoot->rebuildLayoutAttributes();
     80    Vector<SVGTextLayoutAttributes>& layoutAttributes = textRoot->layoutAttributes();
     81    if (layoutAttributes.isEmpty())
    8182        return;
    8283
    83     if (parentBlock->needsReordering())
    84         reorderValueLists(attributes);
     84    if (textRoot->needsReordering())
     85        reorderValueLists(layoutAttributes);
    8586
    8687    // Perform SVG text layout phase two (see SVGTextLayoutEngine for details).
    87     SVGTextLayoutEngine characterLayout(attributes);
     88    SVGTextLayoutEngine characterLayout(layoutAttributes);
    8889    layoutCharactersInTextBoxes(this, characterLayout);
    8990
     
    120121                // Build text chunks for all <textPath> children, using the line layout algorithm.
    121122                // This is needeed as text-anchor is just an additional startOffset for text paths.
    122                 RenderSVGText* parentBlock = toRenderSVGText(block());
    123                 ASSERT(parentBlock);
    124 
    125                 SVGTextLayoutEngine lineLayout(parentBlock->layoutAttributes());
     123                SVGTextLayoutEngine lineLayout(characterLayout.layoutAttributes());
    126124                layoutCharactersInTextBoxes(flowBox, lineLayout);
    127125
     
    222220    return closestLeaf ? closestLeaf : lastLeaf;
    223221}
    224  
    225 static inline void swapItemsInVector(Vector<float>& firstVector, Vector<float>& lastVector, unsigned first, unsigned last)
    226 {
    227     float temp = firstVector.at(first);
    228     firstVector.at(first) = lastVector.at(last);
    229     lastVector.at(last) = temp;
    230 }
    231 
    232 static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes& firstAttributes, SVGTextLayoutAttributes& lastAttributes, unsigned firstPosition, unsigned lastPosition)
    233 {
    234     swapItemsInVector(firstAttributes.xValues(), lastAttributes.xValues(), firstPosition, lastPosition);
    235     swapItemsInVector(firstAttributes.yValues(), lastAttributes.yValues(), firstPosition, lastPosition);
    236     swapItemsInVector(firstAttributes.dxValues(), lastAttributes.dxValues(), firstPosition, lastPosition);
    237     swapItemsInVector(firstAttributes.dyValues(), lastAttributes.dyValues(), firstPosition, lastPosition);
    238     swapItemsInVector(firstAttributes.rotateValues(), lastAttributes.rotateValues(), firstPosition, lastPosition);
     222
     223static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes* firstAttributes, SVGTextLayoutAttributes* lastAttributes, unsigned firstPosition, unsigned lastPosition)
     224{
     225    SVGCharacterDataMap::iterator itFirst = firstAttributes->characterDataMap().find(firstPosition + 1);
     226    SVGCharacterDataMap::iterator itLast = lastAttributes->characterDataMap().find(lastPosition + 1);
     227    bool firstPresent = itFirst != firstAttributes->characterDataMap().end();
     228    bool lastPresent = itLast != lastAttributes->characterDataMap().end();
     229    if (!firstPresent && !lastPresent)
     230        return;
     231
     232    if (firstPresent && lastPresent) {
     233        std::swap(itFirst->second, itLast->second);
     234        return;
     235    }
     236
     237    if (firstPresent && !lastPresent) {
     238        lastAttributes->characterDataMap().set(lastPosition + 1, itFirst->second);
     239        return;
     240    }
     241
     242    // !firstPresent && lastPresent
     243    firstAttributes->characterDataMap().set(firstPosition + 1, itLast->second);
    239244}
    240245
     
    247252    unsigned attributesSize = attributes.size();
    248253    for (unsigned i = 0; i < attributesSize; ++i) {
    249         SVGTextLayoutAttributes& current = attributes.at(i);
     254        SVGTextLayoutAttributes& current = attributes[i];
    250255        if (!first && firstContext == current.context())
    251256            first = &current;
     
    265270    Vector<SVGTextLayoutAttributes>& attributes = *reinterpret_cast<Vector<SVGTextLayoutAttributes>*>(userData);
    266271
    267     // This is a copy of std::reverse(first, last). It additionally assure that the value lists within the InlineBoxes are reordered as well.
     272    // This is a copy of std::reverse(first, last). It additionally assures that the metrics map within the renderers belonging to the InlineBoxes are reordered as well.
    268273    while (true)  {
    269274        if (first == last || first == --last)
     
    289294            SVGTextLayoutAttributes* lastAttributes = 0;
    290295            findFirstAndLastAttributesInVector(attributes, firstContext, lastContext, firstAttributes, lastAttributes);
    291 
    292             unsigned firstBoxPosition = firstTextBox->start();
    293             unsigned firstBoxEnd = firstTextBox->end();
    294 
    295             unsigned lastBoxPosition = lastTextBox->start();
    296             unsigned lastBoxEnd = lastTextBox->end();
    297             for (; firstBoxPosition <= firstBoxEnd && lastBoxPosition <= lastBoxEnd; ++lastBoxPosition, ++firstBoxPosition)
    298                 swapItemsInLayoutAttributes(*firstAttributes, *lastAttributes, firstBoxPosition, lastBoxPosition);
     296            swapItemsInLayoutAttributes(firstAttributes, lastAttributes, firstTextBox->start(), lastTextBox->start());
    299297        }
    300298
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp

    r95901 r105057  
    11/*
    2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
     2 * Copyright (C) Research In Motion Limited 2010-11. All rights reserved.
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    3333}
    3434
    35 void SVGTextLayoutAttributes::reserveCapacity(unsigned length)
     35void SVGTextLayoutAttributes::clear()
    3636{
    37     m_positioningLists.xValues.reserveCapacity(length);
    38     m_positioningLists.yValues.reserveCapacity(length);
    39     m_positioningLists.dxValues.reserveCapacity(length);
    40     m_positioningLists.dyValues.reserveCapacity(length);
    41     m_positioningLists.rotateValues.reserveCapacity(length);
    42     m_textMetricsValues.reserveCapacity(length);
    43 }
    44 
    45 void SVGTextLayoutAttributes::PositioningLists::fillWithEmptyValues(unsigned length)
    46 {
    47     xValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
    48     yValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
    49     dxValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
    50     dyValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
    51     rotateValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
    52 }
    53 
    54 void SVGTextLayoutAttributes::PositioningLists::appendEmptyValues()
    55 {
    56     xValues.append(SVGTextLayoutAttributes::emptyValue());
    57     yValues.append(SVGTextLayoutAttributes::emptyValue());
    58     dxValues.append(SVGTextLayoutAttributes::emptyValue());
    59     dyValues.append(SVGTextLayoutAttributes::emptyValue());
    60     rotateValues.append(SVGTextLayoutAttributes::emptyValue());
    61 }
    62 
    63 static inline float safeValueAtPosition(const Vector<float>& values, unsigned position)
    64 {
    65     return position < values.size() ? values[position] : SVGTextLayoutAttributes::emptyValue();
    66 }
    67 
    68 void SVGTextLayoutAttributes::PositioningLists::appendValuesFromPosition(const PositioningLists& source, unsigned position)
    69 {
    70     xValues.append(safeValueAtPosition(source.xValues, position));
    71     yValues.append(safeValueAtPosition(source.yValues, position));
    72     dxValues.append(safeValueAtPosition(source.dxValues, position));
    73     dyValues.append(safeValueAtPosition(source.dyValues, position));
    74     rotateValues.append(safeValueAtPosition(source.rotateValues, position));
     37    m_characterDataMap.clear();
     38    m_textMetricsValues.clear();
    7539}
    7640
     
    8145}
    8246
    83 static inline void dumpLayoutVector(const Vector<float>& values)
     47static inline void dumpSVGCharacterDataMapValue(const char* identifier, float value, bool appendSpace = true)
    8448{
    85     if (values.isEmpty()) {
    86         fprintf(stderr, "empty");
     49    if (value == SVGTextLayoutAttributes::emptyValue()) {
     50        fprintf(stderr, "%s=x", identifier);
     51        if (appendSpace)
     52            fprintf(stderr, " ");
    8753        return;
    8854    }
    89 
    90     unsigned size = values.size();
    91     for (unsigned i = 0; i < size; ++i) {
    92         float value = values.at(i);
    93         if (value == SVGTextLayoutAttributes::emptyValue())
    94             fprintf(stderr, "x ");
    95         else
    96             fprintf(stderr, "%lf ", value);
    97     }
     55    fprintf(stderr, "%s=%lf", identifier, value);
     56    if (appendSpace)
     57        fprintf(stderr, " ");
    9858}
    9959
     
    10161{
    10262    fprintf(stderr, "context: %p\n", m_context);
    103 
    104     fprintf(stderr, "x values: ");
    105     dumpLayoutVector(m_positioningLists.xValues);
    106     fprintf(stderr, "\n");
    107 
    108     fprintf(stderr, "y values: ");
    109     dumpLayoutVector(m_positioningLists.yValues);
    110     fprintf(stderr, "\n");
    111 
    112     fprintf(stderr, "dx values: ");
    113     dumpLayoutVector(m_positioningLists.dxValues);
    114     fprintf(stderr, "\n");
    115 
    116     fprintf(stderr, "dy values: ");
    117     dumpLayoutVector(m_positioningLists.dyValues);
    118     fprintf(stderr, "\n");
    119 
    120     fprintf(stderr, "rotate values: ");
    121     dumpLayoutVector(m_positioningLists.rotateValues);
    122     fprintf(stderr, "\n");
    123 
    124     fprintf(stderr, "character data values:\n");
    125     unsigned textMetricsSize = m_textMetricsValues.size();
    126     for (unsigned i = 0; i < textMetricsSize; ++i) {
    127         const SVGTextMetrics& metrics = m_textMetricsValues.at(i);
    128         fprintf(stderr, "| {length=%i, glyphName='%s', unicodeString='%s', width=%lf, height=%lf}\n",
    129                 metrics.length(), metrics.glyph().name.utf8().data(), metrics.glyph().unicodeString.utf8().data(), metrics.width(), metrics.height());
     63    const SVGCharacterDataMap::const_iterator end = m_characterDataMap.end();
     64    for (SVGCharacterDataMap::const_iterator it = m_characterDataMap.begin(); it != end; ++it) {
     65        const SVGCharacterData& data = it->second;
     66        fprintf(stderr, " ---> pos=%i, data={", it->first);
     67        dumpSVGCharacterDataMapValue("x", data.x);
     68        dumpSVGCharacterDataMapValue("y", data.y);
     69        dumpSVGCharacterDataMapValue("dx", data.dx);
     70        dumpSVGCharacterDataMapValue("dy", data.dy);
     71        dumpSVGCharacterDataMapValue("rotate", data.rotate, false);
     72        fprintf(stderr, "}\n");
    13073    }
    131     fprintf(stderr, "\n");
    13274}
    13375
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h

    r104926 r105057  
    11/*
    2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
     2 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    4444class SVGTextLayoutAttributes {
    4545public:
    46     // FIXME: This struct will be replaced by SVGCharacterData in a follow up patch.
    47     struct PositioningLists {
    48         void fillWithEmptyValues(unsigned length);
    49         void appendEmptyValues();
    50         void appendValuesFromPosition(const PositioningLists&, unsigned position);
     46    SVGTextLayoutAttributes(RenderSVGInlineText*);
    5147
    52         Vector<float> xValues;
    53         Vector<float> yValues;
    54         Vector<float> dxValues;
    55         Vector<float> dyValues;
    56         Vector<float> rotateValues;
    57     };
    58 
    59     SVGTextLayoutAttributes(RenderSVGInlineText* context = 0);
    60 
    61     // FIXME: Still a no-op, we'll need this once we switch to SVGCharacterDataMap.
    62     void clear() { }
    63     void reserveCapacity(unsigned length);
     48    void clear();
    6449    void dump() const;
    65 
    6650    static float emptyValue();
    6751
    6852    RenderSVGInlineText* context() const { return m_context; }
    69 
    70     PositioningLists& positioningLists() { return m_positioningLists; }
    71     const PositioningLists& positioningLists() const { return m_positioningLists; }
    72 
    73     Vector<float>& xValues() { return m_positioningLists.xValues; }
    74     const Vector<float>& xValues() const { return m_positioningLists.xValues; }
    75 
    76     Vector<float>& yValues() { return m_positioningLists.yValues; }
    77     const Vector<float>& yValues() const { return m_positioningLists.yValues; }
    78 
    79     Vector<float>& dxValues() { return m_positioningLists.dxValues; }
    80     const Vector<float>& dxValues() const { return m_positioningLists.dxValues; }
    81 
    82     Vector<float>& dyValues() { return m_positioningLists.dyValues; }
    83     const Vector<float>& dyValues() const { return m_positioningLists.dyValues; }
    84 
    85     Vector<float>& rotateValues() { return m_positioningLists.rotateValues; }
    86     const Vector<float>& rotateValues() const { return m_positioningLists.rotateValues; }
     53   
     54    SVGCharacterDataMap& characterDataMap() { return m_characterDataMap; }
     55    const SVGCharacterDataMap& characterDataMap() const { return m_characterDataMap; }
    8756
    8857    Vector<SVGTextMetrics>& textMetricsValues() { return m_textMetricsValues; }
    89     const Vector<SVGTextMetrics>& textMetricsValues() const { return m_textMetricsValues; }
    9058
    9159private:
    9260    RenderSVGInlineText* m_context;
    93     PositioningLists m_positioningLists;
     61    SVGCharacterDataMap m_characterDataMap;
    9462    Vector<SVGTextMetrics> m_textMetricsValues;
    9563};
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp

    r104683 r105057  
    3333
    3434SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder()
    35 {
    36 }
    37 
    38 void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextSubtree(RenderSVGText* textRoot)
     35    : m_textLength(0)
     36{
     37}
     38
     39void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer(RenderSVGInlineText* text)
     40{
     41    ASSERT(text);
     42
     43    RenderSVGText* textRoot = RenderSVGText::locateRenderSVGTextAncestor(text);
     44    if (!textRoot)
     45        return;
     46
     47    if (!buildLayoutAttributesIfNeeded(textRoot))
     48        return;
     49
     50    m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap);
     51}
     52
     53void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForWholeTree(RenderSVGText* textRoot)
    3954{
    4055    ASSERT(textRoot);
    4156
    42     // We always clear our current attribute as we don't want to keep any stale ones that could survive DOM modification.
    43     Vector<SVGTextLayoutAttributes>& allAttributes = textRoot->layoutAttributes();
    44     allAttributes.clear();
    45 
    46      // Build list of x/y/dx/dy/rotate values for each subtree element that may define these values (tspan/textPath etc).
    47     unsigned atCharacter = 0;
    48     UChar lastCharacter = '\0';
    49     collectTextPositioningElements(textRoot, atCharacter, lastCharacter);
    50 
    51     if (!atCharacter)
    52         return;
    53 
    54     // Collect x/y/dx/dy/rotate values for each character, stored in the m_positioningLists.xValues()/etc. lists.
    55     buildLayoutAttributesForAllCharacters(textRoot, atCharacter);
    56 
    57     // Propagate layout attributes to each RenderSVGInlineText object, and the whole list to the RenderSVGText root.
    58     atCharacter = 0;
    59     lastCharacter = '\0';
    60     propagateLayoutAttributes(textRoot, allAttributes, atCharacter, lastCharacter);
    61 }
    62 
    63 static inline void extractFloatValuesFromSVGLengthList(SVGElement* contextElement, const SVGLengthList& list, Vector<float>& floatValues, unsigned textContentLength)
    64 {
    65     ASSERT(contextElement);
    66 
    67     unsigned length = list.size();
    68     if (length > textContentLength)
    69         length = textContentLength;
    70     floatValues.reserveCapacity(length);
    71 
    72     SVGLengthContext lengthContext(contextElement);
    73     for (unsigned i = 0; i < length; ++i) {
    74         const SVGLength& length = list.at(i);
    75         floatValues.append(length.value(lengthContext));
    76     }
    77 }
    78 
    79 static inline void extractFloatValuesFromSVGNumberList(const SVGNumberList& list, Vector<float>& floatValues, unsigned textContentLength)
    80 {
    81     unsigned length = list.size();
    82     if (length > textContentLength)
    83         length = textContentLength;
    84     floatValues.reserveCapacity(length);
    85 
    86     for (unsigned i = 0; i < length; ++i)
    87         floatValues.append(list.at(i));
    88 }
    89 
    90 
    91 static inline bool characterIsSpace(const UChar& character)
    92 {
    93     return character == ' ';
    94 }
    95 
    96 static inline bool characterIsSpaceOrNull(const UChar& character)
    97 {
    98     return character == ' ' || character == '\0';
    99 }
    100 
    101 static inline bool shouldPreserveAllWhiteSpace(RenderStyle* style)
    102 {
    103     ASSERT(style);
    104     return style->whiteSpace() == PRE;
    105 }
    106  
    107 static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, UChar& lastCharacter)
    108 {
    109     if (shouldPreserveAllWhiteSpace(text->style())) {
     57    if (!buildLayoutAttributesIfNeeded(textRoot))
     58        return;
     59
     60    m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap);
     61}
     62
     63void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText* text)
     64{
     65    ASSERT(text);
     66    m_metricsBuilder.measureTextRenderer(text);
     67}
     68
     69void SVGTextLayoutAttributesBuilder::rebuildMetricsForWholeTree(RenderSVGText* textRoot)
     70{
     71    ASSERT(textRoot);
     72    Vector<SVGTextLayoutAttributes>& layoutAttributes = textRoot->layoutAttributes();
     73
     74    size_t layoutAttributesSize = layoutAttributes.size();
     75    for (size_t i = 0; i < layoutAttributesSize; ++i)
     76        m_metricsBuilder.measureTextRenderer(layoutAttributes[i].context());
     77}
     78
     79bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesIfNeeded(RenderSVGText* textRoot)
     80{
     81    ASSERT(textRoot);
     82    if (!m_textPositions.isEmpty())
     83        return m_textLength;
     84
     85    m_textLength = 0;
     86    const UChar* lastCharacter = 0;
     87    collectTextPositioningElements(textRoot, lastCharacter);
     88
     89    m_characterDataMap.clear();
     90    if (!m_textLength)
     91        return false;
     92
     93    buildLayoutAttributes(textRoot);
     94    return true;
     95}
     96
     97static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, const UChar*& lastCharacter)
     98{
     99    if (text->style()->whiteSpace() == PRE) {
    110100        atCharacter += text->textLength();
    111101        return;
     
    115105    unsigned textLength = text->textLength();   
    116106    for (unsigned textPosition = 0; textPosition < textLength; ++textPosition) {
    117         const UChar& currentCharacter = characters[textPosition];
    118         if (characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter))
     107        const UChar* currentCharacter = characters + textPosition;
     108        if (*currentCharacter == ' ' && (!lastCharacter || *lastCharacter == ' '))
    119109            continue;
    120110
     
    124114}
    125115
    126 void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter)
     116void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject* start, const UChar*& lastCharacter)
    127117{
    128118    ASSERT(!start->isSVGText() || m_textPositions.isEmpty());
     
    130120    for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
    131121        if (child->isSVGInlineText()) {
    132             processRenderSVGInlineText(toRenderSVGInlineText(child), atCharacter, lastCharacter);
     122            processRenderSVGInlineText(toRenderSVGInlineText(child), m_textLength, lastCharacter);
    133123            continue;
    134124        }
     
    140130        unsigned atPosition = m_textPositions.size();
    141131        if (element)
    142             m_textPositions.append(TextPosition(element, atCharacter));
    143 
    144         collectTextPositioningElements(child, atCharacter, lastCharacter);
     132            m_textPositions.append(TextPosition(element, m_textLength));
     133
     134        collectTextPositioningElements(child, lastCharacter);
    145135
    146136        if (!element)
     
    150140        TextPosition& position = m_textPositions[atPosition];
    151141        ASSERT(!position.length);
    152         position.length = atCharacter - position.start;
    153     }
    154 }
    155 
    156 void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForAllCharacters(RenderSVGText* textRoot, unsigned textLength)
    157 {
    158     ASSERT(textLength);
     142        position.length = m_textLength - position.start;
     143    }
     144}
     145
     146void SVGTextLayoutAttributesBuilder::buildLayoutAttributes(RenderSVGText* textRoot)
     147{
     148    ASSERT(m_textLength);
    159149
    160150    SVGTextPositioningElement* outermostTextElement = SVGTextPositioningElement::elementFromRenderer(textRoot);
    161151    ASSERT(outermostTextElement);
    162152
    163     // Fill the lists with the special emptyValue marker.
    164     m_positioningLists.fillWithEmptyValues(textLength);
    165 
    166     // Grab outermost <text> element value lists and insert them in the m_positioningLists.
    167     TextPosition wholeTextPosition(outermostTextElement, 0, textLength);
    168     fillAttributesAtPosition(wholeTextPosition);
     153    // Grab outermost <text> element value lists and insert them in the character data map.
     154    TextPosition wholeTextPosition(outermostTextElement, 0, m_textLength);
     155    fillCharacterDataMap(wholeTextPosition);
    169156
    170157    // Handle x/y default attributes.
    171     float& xFirst = m_positioningLists.xValues.first();
    172     if (xFirst == SVGTextLayoutAttributes::emptyValue())
    173         xFirst = 0;
    174 
    175     float& yFirst = m_positioningLists.yValues.first();
    176     if (yFirst == SVGTextLayoutAttributes::emptyValue())
    177         yFirst = 0;
    178 
    179     // Fill m_positioningLists using child text positioning elements in top-down order.
     158    SVGCharacterDataMap::iterator it = m_characterDataMap.find(1);
     159    if (it == m_characterDataMap.end()) {
     160        SVGCharacterData data;
     161        data.x = 0;
     162        data.y = 0;
     163        m_characterDataMap.set(1, data);
     164    } else {
     165        SVGCharacterData& data = it->second;
     166        if (data.x == SVGTextLayoutAttributes::emptyValue())
     167            data.x = 0;
     168        if (data.y == SVGTextLayoutAttributes::emptyValue())
     169            data.y = 0;
     170    }
     171
     172    // Fill character data map using child text positioning elements in top-down order.
    180173    unsigned size = m_textPositions.size();
    181174    for (unsigned i = 0; i < size; ++i)
    182         fillAttributesAtPosition(m_textPositions[i]);
    183 
    184     // Now m_positioningLists.contains a x/y/dx/dy/rotate value for each character in the <text> subtree.
    185 }
    186 
    187 void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const
    188 {
    189     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
    190         if (child->isSVGInlineText()) {
    191             RenderSVGInlineText* text = toRenderSVGInlineText(child);
    192             const UChar* characters = text->characters();
    193             unsigned textLength = text->textLength();
    194             bool preserveWhiteSpace = shouldPreserveAllWhiteSpace(text->style());
    195 
    196             SVGTextLayoutAttributes attributes(text);
    197             attributes.reserveCapacity(textLength);
    198    
    199             unsigned valueListPosition = atCharacter;
    200             unsigned metricsLength = 1;
    201             SVGTextMetrics lastMetrics(SVGTextMetrics::SkippedSpaceMetrics);
    202 
    203             for (unsigned textPosition = 0; textPosition < textLength; textPosition += metricsLength) {
    204                 const UChar& currentCharacter = characters[textPosition];
    205 
    206                 SVGTextMetrics startToCurrentMetrics;
    207                 SVGTextMetrics currentMetrics;
    208                 unsigned valueListAdvance = 0;
    209 
    210                 if (U16_IS_LEAD(currentCharacter) && (textPosition + 1) < textLength && U16_IS_TRAIL(characters[textPosition + 1])) {
    211                     // Handle surrogate pairs.
    212                     startToCurrentMetrics = SVGTextMetrics::measureCharacterRange(text, 0, textPosition + 2);
    213                     currentMetrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 2);
    214                     metricsLength = currentMetrics.length();
    215                     valueListAdvance = 1;
    216                 } else {
    217                     // Handle BMP characters.
    218                     startToCurrentMetrics = SVGTextMetrics::measureCharacterRange(text, 0, textPosition + 1);
    219                     currentMetrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1);
    220                     metricsLength = currentMetrics.length();
    221                     valueListAdvance = metricsLength;
    222                 }
    223 
    224                 if (!metricsLength)
    225                     break;
    226                
    227                 // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken
    228                 // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping.
    229                 // So whenever runWidthAdvance != currentMetrics.width(), we are processing a text run whose length is
    230                 // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated.
    231                 float runWidthAdvance = startToCurrentMetrics.width() - lastMetrics.width();
    232                 if (runWidthAdvance != currentMetrics.width())
    233                     currentMetrics.setWidth(runWidthAdvance);
    234 
    235                 lastMetrics = startToCurrentMetrics;
    236 
    237                 if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) {
    238                     attributes.positioningLists().appendEmptyValues();
    239                     attributes.textMetricsValues().append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
    240                     continue;
    241                 }
    242 
    243                 SVGTextLayoutAttributes::PositioningLists& positioningLists = attributes.positioningLists();
    244                 positioningLists.appendValuesFromPosition(m_positioningLists, valueListPosition);
    245                 attributes.textMetricsValues().append(currentMetrics);
    246 
    247                 // Pad x/y/dx/dy/rotate value lists with empty values, if the metrics span more than one character.
    248                 if (metricsLength > 1) {
    249                     for (unsigned i = 0; i < metricsLength - 1; ++i)
    250                         positioningLists.appendEmptyValues();
    251                 }
    252 
    253                 lastCharacter = currentCharacter;
    254                 valueListPosition += valueListAdvance;
    255             }
     175        fillCharacterDataMap(m_textPositions[i]);
    256176
    257177#if DUMP_TEXT_LAYOUT_ATTRIBUTES > 0
    258             fprintf(stderr, "\nDumping layout attributes for RenderSVGInlineText, renderer=%p, node=%p (atCharacter: %i)\n", text, text->node(), atCharacter);
    259             fprintf(stderr, "BiDi properties: unicode-bidi=%i, block direction=%i\n", text->style()->unicodeBidi(), text->style()->direction());
    260             attributes.dump();
     178    fprintf(stderr, "\nDumping ALL layout attributes for RenderSVGText, renderer=%p, node=%p (m_textLength: %i)\n", textRoot, textRoot->node(), m_textLength);
     179    m_characterDataMap.dump();
    261180#endif
    262 
    263             text->storeLayoutAttributes(attributes);
    264             allAttributes.append(attributes);
    265             atCharacter = valueListPosition;
     181}
     182
     183static inline void updateCharacterData(unsigned i, float& lastRotation, SVGCharacterData& data, const SVGLengthContext& lengthContext, const SVGLengthList* xList, const SVGLengthList* yList, const SVGLengthList* dxList, const SVGLengthList* dyList, const SVGNumberList* rotateList)
     184{
     185    if (xList)
     186        data.x = xList->at(i).value(lengthContext);
     187    if (yList)
     188        data.y = yList->at(i).value(lengthContext);
     189    if (dxList)
     190        data.dx = dxList->at(i).value(lengthContext);
     191    if (dyList)
     192        data.dy = dyList->at(i).value(lengthContext);
     193    if (rotateList) {
     194        data.rotate = rotateList->at(i);
     195        lastRotation = data.rotate;
     196    }
     197}
     198
     199void SVGTextLayoutAttributesBuilder::fillCharacterDataMap(const TextPosition& position)
     200{
     201    const SVGLengthList& xList = position.element->x();
     202    const SVGLengthList& yList = position.element->y();
     203    const SVGLengthList& dxList = position.element->dx();
     204    const SVGLengthList& dyList = position.element->dy();
     205    const SVGNumberList& rotateList = position.element->rotate();
     206
     207    unsigned xListSize = xList.size();
     208    unsigned yListSize = yList.size();
     209    unsigned dxListSize = dxList.size();
     210    unsigned dyListSize = dyList.size();
     211    unsigned rotateListSize = rotateList.size();
     212    if (!xListSize && !yListSize && !dxListSize && !dyListSize && !rotateListSize)
     213        return;
     214
     215    float lastRotation = SVGTextLayoutAttributes::emptyValue();
     216    SVGLengthContext lengthContext(position.element);
     217    for (unsigned i = 0; i < position.length; ++i) {
     218        const SVGLengthList* xListPtr = i < xListSize ? &xList : 0;
     219        const SVGLengthList* yListPtr = i < yListSize ? &yList : 0;
     220        const SVGLengthList* dxListPtr = i < dxListSize ? &dxList : 0;
     221        const SVGLengthList* dyListPtr = i < dyListSize ? &dyList : 0;
     222        const SVGNumberList* rotateListPtr = i < rotateListSize ? &rotateList : 0;
     223        if (!xListPtr && !yListPtr && !dxListPtr && !dyListPtr && !rotateListPtr)
     224            break;
     225
     226        SVGCharacterDataMap::iterator it = m_characterDataMap.find(position.start + i + 1);
     227        if (it == m_characterDataMap.end()) {
     228            SVGCharacterData data;
     229            updateCharacterData(i, lastRotation, data, lengthContext, xListPtr, yListPtr, dxListPtr, dyListPtr, rotateListPtr);
     230            m_characterDataMap.set(position.start + i + 1, data);
    266231            continue;
    267232        }
    268233
    269         if (!child->isSVGInline())
    270             continue;
    271 
    272         propagateLayoutAttributes(child, allAttributes, atCharacter, lastCharacter);
    273     }
    274 }
    275 
    276 static inline void fillListAtPosition(Vector<float>& allValues, Vector<float>& values, unsigned start)
    277 {
    278     unsigned valuesSize = values.size();
    279     for (unsigned i = 0; i < valuesSize; ++i)
    280         allValues[start + i] = values[i];
    281 }
    282 
    283 void SVGTextLayoutAttributesBuilder::fillAttributesAtPosition(const TextPosition& position)
    284 {
    285     Vector<float> values;
    286     extractFloatValuesFromSVGLengthList(position.element, position.element->x(), values, position.length);
    287     fillListAtPosition(m_positioningLists.xValues, values, position.start);
    288 
    289     values.clear();
    290     extractFloatValuesFromSVGLengthList(position.element, position.element->y(), values, position.length);
    291     fillListAtPosition(m_positioningLists.yValues, values, position.start);
    292 
    293     values.clear();
    294     extractFloatValuesFromSVGLengthList(position.element, position.element->dx(), values, position.length);
    295     fillListAtPosition(m_positioningLists.dxValues, values, position.start);
    296 
    297     values.clear();
    298     extractFloatValuesFromSVGLengthList(position.element, position.element->dy(), values, position.length);
    299     fillListAtPosition(m_positioningLists.dyValues, values, position.start);
    300 
    301     values.clear();
    302     extractFloatValuesFromSVGNumberList(position.element->rotate(), values, position.length);
    303     fillListAtPosition(m_positioningLists.rotateValues, values, position.start);
     234        updateCharacterData(i, lastRotation, it->second, lengthContext, xListPtr, yListPtr, dxListPtr, dyListPtr, rotateListPtr);
     235    }
    304236
    305237    // The last rotation value always spans the whole scope.
    306     if (values.isEmpty())
    307         return;
    308 
    309     float lastValue = values.last();
    310     for (unsigned i = values.size(); i < position.length; ++i)
    311         m_positioningLists.rotateValues[position.start + i] = lastValue;
     238    if (lastRotation == SVGTextLayoutAttributes::emptyValue())
     239        return;
     240
     241    for (unsigned i = rotateList.size(); i < position.length; ++i) {
     242        SVGCharacterDataMap::iterator it = m_characterDataMap.find(position.start + i + 1);
     243        if (it == m_characterDataMap.end()) {
     244            SVGCharacterData data;
     245            data.rotate = lastRotation;
     246            m_characterDataMap.set(position.start + i + 1, data);
     247            continue;
     248        }
     249
     250        it->second.rotate = lastRotation;
     251    }
    312252}
    313253
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h

    r95901 r105057  
    11/*
    2  * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
     2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved.
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    2222
    2323#if ENABLE(SVG)
    24 #include "SVGTextLayoutAttributes.h"
     24#include "SVGTextMetricsBuilder.h"
    2525#include <wtf/Vector.h>
    2626
     
    2828
    2929class RenderObject;
     30class RenderSVGInlineText;
    3031class RenderSVGText;
    3132class SVGTextPositioningElement;
     
    3334// SVGTextLayoutAttributesBuilder performs the first layout phase for SVG text.
    3435//
    35 // It extracts the x/y/dx/dy/rotate values from the SVGTextPositioningElements in the DOM,
    36 // measures all characters in the RenderSVGText subtree and extracts kerning/ligature information.
     36// It extracts the x/y/dx/dy/rotate values from the SVGTextPositioningElements in the DOM.
    3737// These values are propagated to the corresponding RenderSVGInlineText renderers.
    3838// The first layout phase only extracts the relevant information needed in RenderBlockLineLayout
     
    4444public:
    4545    SVGTextLayoutAttributesBuilder();
    46     void buildLayoutAttributesForTextSubtree(RenderSVGText*);
     46    void buildLayoutAttributesForWholeTree(RenderSVGText*);
     47    void buildLayoutAttributesForTextRenderer(RenderSVGInlineText*);
     48
     49    void rebuildMetricsForWholeTree(RenderSVGText*);
     50    void rebuildMetricsForTextRenderer(RenderSVGInlineText*);
     51
     52    // Invoked whenever the underlying DOM tree changes, so that m_textPositions is rebuild.
     53    void clearTextPositioningElements() { m_textPositions.clear(); }
    4754
    4855private:
     
    6067    };
    6168
    62     void collectTextPositioningElements(RenderObject*, unsigned& atCharacter, UChar& lastCharacter);
    63     void buildLayoutAttributesForAllCharacters(RenderSVGText*, unsigned textLength);
    64     void propagateLayoutAttributes(RenderObject*, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const;
    65     void fillAttributesAtPosition(const TextPosition&);
     69    bool buildLayoutAttributesIfNeeded(RenderSVGText*);
     70    void collectTextPositioningElements(RenderObject*, const UChar*& lastCharacter);
     71    void buildLayoutAttributes(RenderSVGText*);
     72    void fillCharacterDataMap(const TextPosition&);
    6673
    6774private:
     75    unsigned m_textLength;
    6876    Vector<TextPosition> m_textPositions;
    69     SVGTextLayoutAttributes::PositioningLists m_positioningLists;
     77    SVGCharacterDataMap m_characterDataMap;
     78    SVGTextMetricsBuilder m_metricsBuilder;
    7079};
    7180
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp

    r104683 r105057  
    11/*
    2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
     2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved.
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    8585}
    8686
    87 void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues)
     87void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(float dx, float dy)
    8888{
    8989    // Update relative positioning information.
    90     if (dxValues.isEmpty() && dyValues.isEmpty())
     90    if (dx == SVGTextLayoutAttributes::emptyValue() && dy == SVGTextLayoutAttributes::emptyValue())
    9191        return;
    9292
    93     float dx = 0;
    94     if (!dxValues.isEmpty()) {
    95         float& dxCurrent = dxValues.at(m_logicalCharacterOffset);
    96         if (dxCurrent != SVGTextLayoutAttributes::emptyValue())
    97             dx = dxCurrent;
    98     }
    99 
    100     float dy = 0;
    101     if (!dyValues.isEmpty()) {
    102         float& dyCurrent = dyValues.at(m_logicalCharacterOffset);
    103         if (dyCurrent != SVGTextLayoutAttributes::emptyValue())
    104             dy = dyCurrent;
    105     }
     93    if (dx == SVGTextLayoutAttributes::emptyValue())
     94        dx = 0;
     95    if (dy == SVGTextLayoutAttributes::emptyValue())
     96        dy = 0;
    10697
    10798    if (m_inPathLayout) {
     
    345336
    346337    logicalAttributes = m_layoutAttributes.first();
    347     if (m_logicalCharacterOffset != logicalAttributes.xValues().size())
     338    if (m_logicalCharacterOffset != logicalAttributes.context()->textLength())
    348339        return true;
    349340
     
    473464        }
    474465
    475         SVGTextLayoutAttributes logicalAttributes;
     466        SVGTextLayoutAttributes logicalAttributes(0);
    476467        if (!currentLogicalCharacterAttributes(logicalAttributes))
    477468            break;
     
    481472            break;
    482473
    483         Vector<float>& xValues = logicalAttributes.xValues();
    484         Vector<float>& yValues = logicalAttributes.yValues();
    485         Vector<float>& dxValues = logicalAttributes.dxValues();
    486         Vector<float>& dyValues = logicalAttributes.dyValues();
    487         Vector<float>& rotateValues = logicalAttributes.rotateValues();
    488 
    489         float x = xValues.at(m_logicalCharacterOffset);
    490         float y = yValues.at(m_logicalCharacterOffset);
     474        SVGCharacterDataMap& characterDataMap = logicalAttributes.characterDataMap();
     475        SVGCharacterData data;
     476        SVGCharacterDataMap::iterator it = characterDataMap.find(m_logicalCharacterOffset + 1);
     477        if (it != characterDataMap.end())
     478            data = it->second;
     479
     480        float x = data.x;
     481        float y = data.y;
    491482
    492483        // When we've advanced to the box start offset, determine using the original x/y values,
     
    495486            textBox->setStartsNewTextChunk(logicalAttributes.context()->characterStartsNewTextChunk(m_logicalCharacterOffset));
    496487
    497         float angle = 0;
    498         if (!rotateValues.isEmpty()) {
    499             float newAngle = rotateValues.at(m_logicalCharacterOffset);
    500             if (newAngle != SVGTextLayoutAttributes::emptyValue())
    501                 angle = newAngle;
    502         }
     488        float angle = data.rotate == SVGTextLayoutAttributes::emptyValue() ? 0 : data.rotate;
    503489
    504490        // Calculate glyph orientation angle.
     
    515501
    516502        // Apply dx/dy value adjustments to current text position, if needed.
    517         updateRelativePositionAdjustmentsIfNeeded(dxValues, dyValues);
     503        updateRelativePositionAdjustmentsIfNeeded(data.dx, data.dy);
    518504
    519505        // Calculate SVG Fonts kerning, if needed.
  • trunk/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h

    r95901 r105057  
    11/*
    2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
     2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved.
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    5858    void finishLayout();
    5959
     60    Vector<SVGTextLayoutAttributes>& layoutAttributes() { return m_layoutAttributes; }
     61
    6062private:
    6163    void updateCharacerPositionIfNeeded(float& x, float& y);
    6264    void updateCurrentTextPosition(float x, float y, float glyphAdvance);
    63     void updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues);
     65    void updateRelativePositionAdjustmentsIfNeeded(float dx, float dy);
    6466
    6567    void recordTextFragment(SVGInlineTextBox*, Vector<SVGTextMetrics>& textMetricValues);
  • trunk/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp

    r104926 r105057  
    2626#include "RenderSVGText.h"
    2727#include "SVGTextRunRenderingContext.h"
    28 #include "WidthIterator.h"
    2928
    3029namespace WebCore {
     
    5352    advanceComplexText();
    5453#else
     54    // FIXME: Enabling the simple code path, affects some layout test results, so this will be landed seperated.
     55    m_isComplexText = true;
    5556    if (m_isComplexText)
    5657        advanceComplexText();
     
    9293    m_currentMetrics = SVGTextMetrics::measureCharacterRange(m_text, m_textPosition, metricsLength);
    9394    m_complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, 0, m_textPosition + metricsLength);
    94     ASSERT(m_currentMetrics.length() == metricsLength);
     95
     96    // FIXME: Re-enable this assertion, once SVG Fonts stop using this code path.
     97    // ASSERT(m_currentMetrics.length() == metricsLength);
    9598
    9699    // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken
     
    171174            if (data->allCharactersMap) {
    172175                const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + m_textPosition - data->skippedCharacters + 1);
    173                 if (it != data->allCharactersMap->end()) {
    174                     // FIXME: Yes this is nonsense for now. This will use attributes->characterDataMap(), as soon as its available, in a follow-up commit.
    175                     SVGCharacterDataMap map;
    176                     map.set(m_textPosition + 1, it->second);
    177                 }
     176                if (it != data->allCharactersMap->end())
     177                    attributes->characterDataMap().set(m_textPosition + 1, it->second);
    178178            }
    179179            textMetricsValues->append(m_currentMetrics);
  • trunk/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.h

    r104926 r105057  
    2525#include "SVGTextMetrics.h"
    2626#include "TextRun.h"
     27#include "WidthIterator.h"
    2728#include <wtf/Vector.h>
    2829
     
    3334class RenderSVGText;
    3435struct MeasureTextData;
    35 struct WidthIterator;
    3636
    3737class SVGTextMetricsBuilder {
  • trunk/Source/WebCore/rendering/svg/SVGTextQuery.cpp

    r95901 r105057  
    11/*
    2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
     2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved.
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    159159void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, int& startPosition, int& endPosition) const
    160160{
    161     const SVGTextLayoutAttributes& layoutAttributes = queryData->textRenderer->layoutAttributes();
    162     const Vector<float>& xValues = layoutAttributes.xValues();
    163     const Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes.textMetricsValues();
    164 
     161    SVGTextLayoutAttributes& layoutAttributes = queryData->textRenderer->layoutAttributes();
     162    Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes.textMetricsValues();
    165163    unsigned boxStart = queryData->textBox->start();
    166164    unsigned boxLength = queryData->textBox->len();
     
    170168
    171169    unsigned positionOffset = 0;
    172     unsigned positionSize = xValues.size();
     170    unsigned positionSize = layoutAttributes.context()->textLength();
    173171
    174172    bool alterStartPosition = true;
     
    177175    int lastPositionOffset = -1;
    178176    for (; textMetricsOffset < textMetricsSize && positionOffset < positionSize; ++textMetricsOffset) {
    179         const SVGTextMetrics& metrics = textMetricsValues.at(textMetricsOffset);
     177        SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset];
    180178
    181179        // Advance to text box start location.
Note: See TracChangeset for help on using the changeset viewer.