Beispiel #1
0
void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk)
{
    bool processTextLength = chunk.hasDesiredTextLength();
    bool processTextAnchor = chunk.hasTextAnchor();
    if (!processTextAnchor && !processTextLength)
        return;

    const Vector<SVGInlineTextBox*>& boxes = chunk.boxes();
    unsigned boxCount = boxes.size();
    if (!boxCount)
        return;

    // Calculate absolute length of whole text chunk (starting from text box 'start', spanning 'length' text boxes).
    float chunkLength = 0;
    unsigned chunkCharacters = 0;
    chunk.calculateLength(chunkLength, chunkCharacters);

    bool isVerticalText = chunk.isVerticalText();
    if (processTextLength) {
        if (chunk.hasLengthAdjustSpacing()) {
            float textLengthShift = (chunk.desiredTextLength() - chunkLength) / chunkCharacters;
            unsigned atCharacter = 0;
            for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
                Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments();
                if (fragments.isEmpty())
                    continue;
                processTextLengthSpacingCorrection(isVerticalText, textLengthShift, fragments, atCharacter);
            }
        } else {
            ASSERT(chunk.hasLengthAdjustSpacingAndGlyphs());
            float textLengthScale = chunk.desiredTextLength() / chunkLength;
            AffineTransform spacingAndGlyphsTransform;

            bool foundFirstFragment = false;
            for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
                SVGInlineTextBox* textBox = boxes[boxPosition];
                Vector<SVGTextFragment>& fragments = textBox->textFragments();
                if (fragments.isEmpty())
                    continue;

                if (!foundFirstFragment) {
                    foundFirstFragment = true;
                    buildSpacingAndGlyphsTransform(isVerticalText, textLengthScale, fragments.first(), spacingAndGlyphsTransform);
                }

                m_textBoxTransformations.set(textBox, spacingAndGlyphsTransform);
            }
        }
    }

    if (!processTextAnchor)
        return;

    // If we previously applied a lengthAdjust="spacing" correction, we have to recalculate the chunk length, to be able to apply the text-anchor shift.
    if (processTextLength && chunk.hasLengthAdjustSpacing()) {
        chunkLength = 0;
        chunkCharacters = 0;
        chunk.calculateLength(chunkLength, chunkCharacters);
    }

    float textAnchorShift = chunk.calculateTextAnchorShift(chunkLength);
    for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
        Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments();
        if (fragments.isEmpty())
            continue;
        processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments);
    }
}
void SVGTextChunkBuilder::handleTextChunk(BoxListConstIterator boxStart,
                                          BoxListConstIterator boxEnd) {
  ASSERT(*boxStart);

  const LineLayoutSVGInlineText textLineLayout =
      LineLayoutSVGInlineText((*boxStart)->getLineLayoutItem());
  const ComputedStyle& style = textLineLayout.styleRef();

  // Handle 'lengthAdjust' property.
  float desiredTextLength = 0;
  SVGLengthAdjustType lengthAdjust = SVGLengthAdjustUnknown;
  if (SVGTextContentElement* textContentElement =
          SVGTextContentElement::elementFromLineLayoutItem(
              textLineLayout.parent())) {
    lengthAdjust =
        textContentElement->lengthAdjust()->currentValue()->enumValue();

    SVGLengthContext lengthContext(textContentElement);
    if (textContentElement->textLengthIsSpecifiedByUser())
      desiredTextLength =
          textContentElement->textLength()->currentValue()->value(
              lengthContext);
    else
      desiredTextLength = 0;
  }

  bool processTextLength = desiredTextLength > 0;
  bool processTextAnchor = needsTextAnchorAdjustment(style);
  if (!processTextAnchor && !processTextLength)
    return;

  bool isVerticalText = !style.isHorizontalWritingMode();

  // Calculate absolute length of whole text chunk (starting from text box
  // 'start', spanning 'length' text boxes).
  ChunkLengthAccumulator lengthAccumulator(isVerticalText);
  lengthAccumulator.processRange(boxStart, boxEnd);

  if (processTextLength) {
    float chunkLength = lengthAccumulator.length();
    if (lengthAdjust == SVGLengthAdjustSpacing) {
      float textLengthShift =
          (desiredTextLength - chunkLength) / lengthAccumulator.numCharacters();
      unsigned atCharacter = 0;
      for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) {
        Vector<SVGTextFragment>& fragments = (*boxIter)->textFragments();
        if (fragments.isEmpty())
          continue;
        processTextLengthSpacingCorrection(isVerticalText, textLengthShift,
                                           fragments, atCharacter);
      }

      // Fragments have been adjusted, we have to recalculate the chunk
      // length, to be able to apply the text-anchor shift.
      if (processTextAnchor) {
        lengthAccumulator.reset();
        lengthAccumulator.processRange(boxStart, boxEnd);
      }
    } else {
      ASSERT(lengthAdjust == SVGLengthAdjustSpacingAndGlyphs);
      float textLengthScale = desiredTextLength / chunkLength;
      float textLengthBias = 0;

      bool foundFirstFragment = false;
      for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) {
        SVGInlineTextBox* textBox = *boxIter;
        Vector<SVGTextFragment>& fragments = textBox->textFragments();
        if (fragments.isEmpty())
          continue;

        if (!foundFirstFragment) {
          foundFirstFragment = true;
          textLengthBias =
              computeTextLengthBias(fragments.first(), textLengthScale);
        }

        applyTextLengthScaleAdjustment(textLengthScale, textLengthBias,
                                       fragments);
      }
    }
  }

  if (!processTextAnchor)
    return;

  float textAnchorShift =
      calculateTextAnchorShift(style, lengthAccumulator.length());
  for (auto boxIter = boxStart; boxIter != boxEnd; ++boxIter) {
    Vector<SVGTextFragment>& fragments = (*boxIter)->textFragments();
    if (fragments.isEmpty())
      continue;
    processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments);
  }
}