This source file includes following definitions.
- paint
- markDirty
- computePerCharacterLayoutInformation
- layoutCharactersInTextBoxes
- layoutChildBoxes
- layoutRootBox
- closestLeafChildForPosition
- swapItemsInLayoutAttributes
- findFirstAndLastAttributesInVector
- reverseInlineBoxRangeAndValueListsIfNeeded
- reorderValueLists
#include "config.h"
#include "core/rendering/svg/SVGRootInlineBox.h"
#include "SVGNames.h"
#include "core/rendering/svg/RenderSVGInlineText.h"
#include "core/rendering/svg/RenderSVGText.h"
#include "core/rendering/svg/SVGInlineFlowBox.h"
#include "core/rendering/svg/SVGInlineTextBox.h"
#include "core/rendering/svg/SVGRenderingContext.h"
namespace WebCore {
void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit)
{
ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
ASSERT(!paintInfo.context->paintingDisabled());
bool isPrinting = renderer().document().printing();
bool hasSelection = !isPrinting && selectionState() != RenderObject::SelectionNone;
PaintInfo childPaintInfo(paintInfo);
if (hasSelection) {
for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
if (child->isSVGInlineTextBox())
toSVGInlineTextBox(child)->paintSelectionBackground(childPaintInfo);
else if (child->isSVGInlineFlowBox())
toSVGInlineFlowBox(child)->paintSelectionBackground(childPaintInfo);
}
}
SVGRenderingContext renderingContext(&renderer(), paintInfo, SVGRenderingContext::SaveGraphicsContext);
if (renderingContext.isRenderingPrepared()) {
for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
child->paint(paintInfo, paintOffset, 0, 0);
}
}
void SVGRootInlineBox::markDirty(bool dirty)
{
if (dirty)
for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
child->markDirty(true);
RootInlineBox::markDirty(dirty);
}
void SVGRootInlineBox::computePerCharacterLayoutInformation()
{
RenderSVGText& textRoot = toRenderSVGText(block());
Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot.layoutAttributes();
if (layoutAttributes.isEmpty())
return;
if (textRoot.needsReordering())
reorderValueLists(layoutAttributes);
SVGTextLayoutEngine characterLayout(layoutAttributes);
layoutCharactersInTextBoxes(this, characterLayout);
characterLayout.finishLayout();
FloatRect childRect;
layoutChildBoxes(this, &childRect);
layoutRootBox(childRect);
}
void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGTextLayoutEngine& characterLayout)
{
for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) {
if (child->isSVGInlineTextBox()) {
ASSERT(child->renderer().isSVGInlineText());
characterLayout.layoutInlineTextBox(toSVGInlineTextBox(child));
} else {
Node* node = child->renderer().node();
if (!node)
continue;
SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child);
bool isTextPath = isSVGTextPathElement(*node);
if (isTextPath) {
SVGTextLayoutEngine lineLayout(characterLayout.layoutAttributes());
layoutCharactersInTextBoxes(flowBox, lineLayout);
characterLayout.beginTextPathLayout(&child->renderer(), lineLayout);
}
layoutCharactersInTextBoxes(flowBox, characterLayout);
if (isTextPath)
characterLayout.endTextPathLayout();
}
}
}
void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRect)
{
for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) {
FloatRect boxRect;
if (child->isSVGInlineTextBox()) {
ASSERT(child->renderer().isSVGInlineText());
SVGInlineTextBox* textBox = toSVGInlineTextBox(child);
boxRect = textBox->calculateBoundaries();
textBox->setX(boxRect.x());
textBox->setY(boxRect.y());
textBox->setLogicalWidth(boxRect.width());
textBox->setLogicalHeight(boxRect.height());
} else {
if (!child->renderer().node())
continue;
SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child);
layoutChildBoxes(flowBox);
boxRect = flowBox->calculateBoundaries();
flowBox->setX(boxRect.x());
flowBox->setY(boxRect.y());
flowBox->setLogicalWidth(boxRect.width());
flowBox->setLogicalHeight(boxRect.height());
}
if (childRect)
childRect->unite(boxRect);
}
}
void SVGRootInlineBox::layoutRootBox(const FloatRect& childRect)
{
RenderBlockFlow& parentBlock = block();
LayoutRect boundingRect = enclosingLayoutRect(childRect);
parentBlock.setLocation(boundingRect.location());
parentBlock.setSize(boundingRect.size());
for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) {
if (!child->renderer().node())
continue;
child->adjustPosition(-childRect.x(), -childRect.y());
}
setX(0);
setY(0);
setLogicalWidth(childRect.width());
setLogicalHeight(childRect.height());
setLineTopBottomPositions(0, boundingRect.height(), 0, boundingRect.height());
}
InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const LayoutPoint& point)
{
InlineBox* firstLeaf = firstLeafChild();
InlineBox* lastLeaf = lastLeafChild();
if (firstLeaf == lastLeaf)
return firstLeaf;
InlineBox* closestLeaf = 0;
for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChild()) {
if (!leaf->isSVGInlineTextBox())
continue;
if (point.y() < leaf->y())
continue;
if (point.y() > leaf->y() + leaf->virtualLogicalHeight())
continue;
closestLeaf = leaf;
if (point.x() < leaf->left() + leaf->logicalWidth())
return leaf;
}
return closestLeaf ? closestLeaf : lastLeaf;
}
static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes* firstAttributes, SVGTextLayoutAttributes* lastAttributes, unsigned firstPosition, unsigned lastPosition)
{
SVGCharacterDataMap::iterator itFirst = firstAttributes->characterDataMap().find(firstPosition + 1);
SVGCharacterDataMap::iterator itLast = lastAttributes->characterDataMap().find(lastPosition + 1);
bool firstPresent = itFirst != firstAttributes->characterDataMap().end();
bool lastPresent = itLast != lastAttributes->characterDataMap().end();
if (!firstPresent || !lastPresent)
return;
std::swap(itFirst->value, itLast->value);
}
static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes*>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext,
SVGTextLayoutAttributes*& first, SVGTextLayoutAttributes*& last)
{
first = 0;
last = 0;
unsigned attributesSize = attributes.size();
for (unsigned i = 0; i < attributesSize; ++i) {
SVGTextLayoutAttributes* current = attributes[i];
if (!first && firstContext == current->context())
first = current;
if (!last && lastContext == current->context())
last = current;
if (first && last)
break;
}
ASSERT(first);
ASSERT(last);
}
static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last)
{
ASSERT(userData);
Vector<SVGTextLayoutAttributes*>& attributes = *reinterpret_cast<Vector<SVGTextLayoutAttributes*>*>(userData);
while (true) {
if (first == last || first == --last)
return;
if (!(*last)->isSVGInlineTextBox() || !(*first)->isSVGInlineTextBox()) {
InlineBox* temp = *first;
*first = *last;
*last = temp;
++first;
continue;
}
SVGInlineTextBox* firstTextBox = toSVGInlineTextBox(*first);
SVGInlineTextBox* lastTextBox = toSVGInlineTextBox(*last);
if (firstTextBox->len() == 1 && firstTextBox->len() == lastTextBox->len()) {
RenderSVGInlineText& firstContext = toRenderSVGInlineText(firstTextBox->textRenderer());
RenderSVGInlineText& lastContext = toRenderSVGInlineText(lastTextBox->textRenderer());
SVGTextLayoutAttributes* firstAttributes = 0;
SVGTextLayoutAttributes* lastAttributes = 0;
findFirstAndLastAttributesInVector(attributes, &firstContext, &lastContext, firstAttributes, lastAttributes);
swapItemsInLayoutAttributes(firstAttributes, lastAttributes, firstTextBox->start(), lastTextBox->start());
}
InlineBox* temp = *first;
*first = *last;
*last = temp;
++first;
}
}
void SVGRootInlineBox::reorderValueLists(Vector<SVGTextLayoutAttributes*>& attributes)
{
Vector<InlineBox*> leafBoxesInLogicalOrder;
collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder, reverseInlineBoxRangeAndValueListsIfNeeded, &attributes);
}
}