static void placeBoxesVerticallyWithAbsBaseline(InlineFlowBox* flow, int& heightOfBlock, int& minY, int& maxY, int& baseline, int yPos) { for (InlineBox* curr = flow->firstChild(); curr; curr = curr->nextOnLine()) { if (curr->isInlineFlowBox() && !curr->object()->element()->hasTagName(aTag)) { SVGTextPositioningElement* text = static_cast<SVGTextPositioningElement*>(curr->object()->element()); baseline += (int)(text->dy()->getFirst().value()); if (text->y()->numberOfItems() > 0) baseline = (int)(text->y()->getFirst().value() - yPos); placeBoxesVerticallyWithAbsBaseline(static_cast<InlineFlowBox*>(curr), heightOfBlock, minY, maxY, baseline, yPos); } const Font& font = curr->object()->firstLineStyle()->font(); // FIXME: Is it right to always use firstLineStyle here? int ascent = font.ascent(); int position = baseline - ascent; int height = ascent + font.descent(); curr->setBaseline(ascent); curr->setYPos(position); curr->setHeight(height); if (position < minY) minY = position; if (position + height > maxY) maxY = position + height; } if (flow->isRootInlineBox()) { flow->setYPos(minY); flow->setHeight(maxY - minY); flow->setBaseline(baseline - minY); heightOfBlock += maxY - minY; } }
void SVGTextLayoutAttributesBuilder::buildLayoutScope(LayoutScope& scope, RenderObject* renderer, unsigned textContentStart, unsigned textContentLength) const { ASSERT(renderer); ASSERT(renderer->style()); scope.textContentStart = textContentStart; scope.textContentLength = textContentLength; SVGTextPositioningElement* element = SVGTextPositioningElement::elementFromRenderer(renderer); if (!element) return; SVGTextLayoutAttributes& attributes = scope.attributes; extractFloatValuesFromSVGLengthList(element, element->x(), attributes.xValues(), textContentLength); extractFloatValuesFromSVGLengthList(element, element->y(), attributes.yValues(), textContentLength); extractFloatValuesFromSVGLengthList(element, element->dx(), attributes.dxValues(), textContentLength); extractFloatValuesFromSVGLengthList(element, element->dy(), attributes.dyValues(), textContentLength); extractFloatValuesFromSVGNumberList(element->rotate(), attributes.rotateValues(), textContentLength); // The last rotation value spans the whole scope. Vector<float>& rotateValues = attributes.rotateValues(); if (rotateValues.isEmpty()) return; unsigned rotateValuesSize = rotateValues.size(); if (rotateValuesSize == textContentLength) return; float lastRotation = rotateValues.last(); rotateValues.resize(textContentLength); for (unsigned i = rotateValuesSize; i < textContentLength; ++i) rotateValues.at(i) = lastRotation; }
static bool translateBox(InlineBox* box, int x, int y, bool topLevel) { if (box->object()->isText()) { box->setXPos(box->xPos() + x); box->setYPos(box->yPos() + y); } else if (!box->object()->element()->hasTagName(aTag)) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(box); SVGTextPositioningElement* text = static_cast<SVGTextPositioningElement*>(box->object()->element()); if (topLevel || !(text->x()->getFirst().value() || text->y()->getFirst().value() || text->dx()->getFirst().value() || text->dy()->getFirst().value())) { box->setXPos(box->xPos() + x); box->setYPos(box->yPos() + y); for (InlineBox* curr = flow->firstChild(); curr; curr = curr->nextOnLine()) { if (!translateBox(curr, x, y, false)) return false; } } } return true; }
static int placePositionedBoxesHorizontally(InlineFlowBox* flow, int x, int& leftPosition, int& rightPosition, int& leftAlign, int& rightAlign, bool& needsWordSpacing, int xPos, bool positioned) { int mn = INT_MAX; int mx = INT_MIN; int amn = INT_MAX; int amx = INT_MIN; int startx = x; bool seenPositionedElement = false; flow->setXPos(x); for (InlineBox* curr = flow->firstChild(); curr; curr = curr->nextOnLine()) { if (curr->object()->isText()) { mn = min(mn, x); amn = min(amn, x); InlineTextBox* text = static_cast<InlineTextBox*>(curr); RenderText* rt = static_cast<RenderText*>(text->object()); if (rt->textLength()) { if (needsWordSpacing && DeprecatedChar(rt->characters()[text->start()]).isSpace()) x += rt->style(flow->isFirstLineStyle())->font().wordSpacing(); needsWordSpacing = !DeprecatedChar(rt->characters()[text->end()]).isSpace(); } text->setXPos(x); x += text->width(); mx = max(mx, x); amx = max(amx, x); } else if (curr->object()->isInlineFlow()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); if (flow->object()->element()->hasTagName(aTag)) { x = placePositionedBoxesHorizontally(flow, x, mn, mx, amn, amx, needsWordSpacing, xPos, false); } else { SVGTextPositioningElement* text = static_cast<SVGTextPositioningElement*>(flow->object()->element()); x += (int)(text->dx()->getFirst().value()); if (text->x()->numberOfItems() > 0) x = (int)(text->x()->getFirst().value() - xPos); if (text->x()->numberOfItems() > 0 || text->y()->numberOfItems() > 0 || text->dx()->numberOfItems() > 0 || text->dy()->numberOfItems() > 0) { seenPositionedElement = true; needsWordSpacing = false; int ignoreX, ignoreY; x = placePositionedBoxesHorizontally(flow, x, mn, mx, ignoreX, ignoreY, needsWordSpacing, xPos, true); } else if (seenPositionedElement) { int ignoreX, ignoreY; x = placePositionedBoxesHorizontally(flow, x, mn, mx, ignoreX, ignoreY, needsWordSpacing, xPos, false); } else x = placePositionedBoxesHorizontally(flow, x, mn, mx, amn, amx, needsWordSpacing, xPos, false); } } } if (mn > mx) mn = mx = startx; if (amn > amx) amn = amx = startx; int width = mx - mn; flow->setWidth(width); int awidth = amx - amn; int dx = 0; if (positioned) { switch (flow->object()->style()->svgStyle()->textAnchor()) { case TA_MIDDLE: translateBox(flow, dx = -awidth / 2, 0, true); break; case TA_END: translateBox(flow, dx = -awidth, 0, true); break; case TA_START: default: break; } if (dx) { x += dx; mn += dx; mx += dx; } } leftPosition = min(leftPosition, mn); rightPosition = max(rightPosition, mx); leftAlign = min(leftAlign, amn); rightAlign = max(rightAlign, amx); return x; }