void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); bool isPrinting = renderSVGText().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(renderSVGText(), paintInfo, SVGRenderingContext::SaveGraphicsContext); if (renderingContext.isRenderingPrepared()) { for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(&toSVGInlineTextBox(child)->renderer()); child->paint(paintInfo, LayoutPoint(), 0, 0); } } }
void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); RenderObject* boxRenderer = renderer(); ASSERT(boxRenderer); 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()) static_cast<SVGInlineTextBox*>(child)->paintSelectionBackground(childPaintInfo); else if (child->isSVGInlineFlowBox()) static_cast<SVGInlineFlowBox*>(child)->paintSelectionBackground(childPaintInfo); } } childPaintInfo.context->save(); if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo)) { for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer())); child->paint(childPaintInfo, 0, 0); } } SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, paintInfo.context); childPaintInfo.context->restore(); }
void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGTextLayoutEngine& characterLayout) { for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) { ASSERT(child->renderer().isSVGInlineText()); SVGInlineTextBox* textBox = toSVGInlineTextBox(child); characterLayout.layoutInlineTextBox(textBox); } else { // Skip generated content. Node* node = child->renderer().node(); if (!node) continue; ASSERT_WITH_SECURITY_IMPLICATION(child->isInlineFlowBox()); SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); bool isTextPath = node->hasTagName(SVGNames::textPathTag); if (isTextPath) { // Build text chunks for all <textPath> children, using the line layout algorithm. // This is needeed as text-anchor is just an additional startOffset for text paths. 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 { // Skip generated content. if (!child->renderer().node()) continue; ASSERT_WITH_SECURITY_IMPLICATION(child->isInlineFlowBox()); 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::layoutChildBoxes(InlineFlowBox* start) { for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) { ASSERT(child->renderer()); ASSERT(child->renderer()->isSVGInlineText()); SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child); IntRect boxRect = textBox->calculateBoundaries(); textBox->setX(boxRect.x()); textBox->setY(boxRect.y()); textBox->setLogicalWidth(boxRect.width()); textBox->setLogicalHeight(boxRect.height()); } else { ASSERT(child->isInlineFlowBox()); // Skip generated content. if (!child->renderer()->node()) continue; SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child); layoutChildBoxes(flowBox); IntRect boxRect = flowBox->calculateBoundaries(); flowBox->setX(boxRect.x()); flowBox->setY(boxRect.y()); flowBox->setLogicalWidth(boxRect.width()); flowBox->setLogicalHeight(boxRect.height()); } } }
void SVGTextLayoutEngine::layoutCharactersInTextBoxes(InlineFlowBox* start) { bool textLengthSpacingInEffect = m_textLengthSpacingInEffect || definesTextLengthWithSpacing(start); TemporaryChange<bool> textLengthSpacingScope(m_textLengthSpacingInEffect, textLengthSpacingInEffect); for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) { ASSERT(child->layoutObject().isSVGInlineText()); layoutInlineTextBox(toSVGInlineTextBox(child)); } else { // Skip generated content. Node* node = child->layoutObject().node(); if (!node) continue; SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); bool isTextPath = isSVGTextPathElement(*node); if (isTextPath) beginTextPathLayout(flowBox); layoutCharactersInTextBoxes(flowBox); if (isTextPath) endTextPathLayout(); } } }
void SVGRootInlineBoxPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); bool hasSelection = !paintInfo.isPrinting() && m_svgRootInlineBox.selectionState() != SelectionNone; PaintInfo paintInfoBeforeFiltering(paintInfo); if (hasSelection && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfoBeforeFiltering.context, m_svgRootInlineBox.layoutObject(), paintInfoBeforeFiltering.phase, paintOffset)) { LayoutObjectDrawingRecorder recorder(*paintInfoBeforeFiltering.context, m_svgRootInlineBox.layoutObject(), paintInfoBeforeFiltering.phase, paintInfoBeforeFiltering.cullRect().m_rect, paintOffset); for (InlineBox* child = m_svgRootInlineBox.firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) SVGInlineTextBoxPainter(*toSVGInlineTextBox(child)).paintSelectionBackground(paintInfoBeforeFiltering); else if (child->isSVGInlineFlowBox()) SVGInlineFlowBoxPainter(*toSVGInlineFlowBox(child)).paintSelectionBackground(paintInfoBeforeFiltering); } } SVGPaintContext paintContext(m_svgRootInlineBox.layoutObject(), paintInfoBeforeFiltering); if (paintContext.applyClipMaskAndFilterIfNecessary()) { for (InlineBox* child = m_svgRootInlineBox.firstChild(); child; child = child->nextOnLine()) child->paint(paintContext.paintInfo(), paintOffset, 0, 0); } }
LayoutRect SVGInlineFlowBox::calculateBoundaries() const { LayoutRect childRect; for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { if (!child->isSVGInlineTextBox() && !child->isSVGInlineFlowBox()) continue; childRect.unite(child->calculateBoundaries()); } return childRect; }
bool SVGRootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom, HitTestAction hitTestAction) { for (InlineBox* leaf = firstLeafChild(); leaf; leaf = leaf->nextLeafChild()) { if (!leaf->isSVGInlineTextBox()) continue; if (leaf->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom, hitTestAction)) return true; } return false; }
void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); PaintInfo childPaintInfo(paintInfo); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) toSVGInlineTextBox(child)->paintSelectionBackground(childPaintInfo); else if (child->isSVGInlineFlowBox()) toSVGInlineFlowBox(child)->paintSelectionBackground(childPaintInfo); } }
void SVGInlineFlowBoxPainter::paintSelectionBackground(const PaintInfo& paintInfo) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); PaintInfo childPaintInfo(paintInfo); for (InlineBox* child = m_svgInlineFlowBox.firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) SVGInlineTextBoxPainter(*toSVGInlineTextBox(child)).paintSelectionBackground(childPaintInfo); else if (child->isSVGInlineFlowBox()) SVGInlineFlowBoxPainter(*toSVGInlineFlowBox(child)).paintSelectionBackground(childPaintInfo); } }
void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); PaintInfo childPaintInfo(paintInfo); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) static_cast<SVGInlineTextBox*>(child)->paintSelectionBackground(childPaintInfo); else if (child->isSVGInlineFlowBox()) static_cast<SVGInlineFlowBox*>(child)->paintSelectionBackground(childPaintInfo); } }
void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); RenderObject* boxRenderer = renderer(); ASSERT(boxRenderer); SVGRenderingContext renderingContext(boxRenderer, paintInfo, SVGRenderingContext::SaveGraphicsContext); if (renderingContext.isRenderingPrepared()) { for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer())); child->paint(paintInfo, LayoutPoint(), 0, 0); } } }
static void collectTextBoxesInFlowBox(InlineFlowBox* flowBox, Vector<SVGInlineTextBox*>& textBoxes) { if (!flowBox) return; for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) { if (child->isInlineFlowBox()) { // Skip generated content. if (!child->layoutObject().node()) continue; collectTextBoxesInFlowBox(toInlineFlowBox(child), textBoxes); continue; } if (child->isSVGInlineTextBox()) textBoxes.append(toSVGInlineTextBox(child)); } }
void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox) { if (!flowBox) return; for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) { if (child->isInlineFlowBox()) { // Skip generated content. if (!child->renderer()->node()) continue; collectTextBoxesInFlowBox(toInlineFlowBox(child)); continue; } if (child->isSVGInlineTextBox()) m_textBoxes.append(toSVGInlineTextBox(child)); } }
void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); RenderObject* boxRenderer = renderer(); ASSERT(boxRenderer); PaintInfo childPaintInfo(paintInfo); GraphicsContextStateSaver stateSaver(*childPaintInfo.context); if (SVGRenderSupport::prepareToRenderSVGContent(boxRenderer, childPaintInfo)) { for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer())); child->paint(childPaintInfo, LayoutPoint(), 0, 0); } } SVGRenderSupport::finishRenderSVGContent(boxRenderer, childPaintInfo, paintInfo.context); }
static void applyTextAnchorToTextChunk(SVGTextChunk& chunk) { // This method is not called for chunks containing chars aligned on a path. // -> all characters are visible, no need to check for "isHidden()" anywhere. if (chunk.anchor == TA_START) return; float shift = calculateTextAnchorShiftForTextChunk(chunk, chunk.anchor); // Apply correction to chunk Vector<SVGChar>::iterator chunkIt = chunk.start; for (; chunkIt != chunk.end; ++chunkIt) { SVGChar& curChar = *chunkIt; if (chunk.isVerticalText) curChar.y += shift; else curChar.x += shift; } // Move inline boxes Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin(); Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end(); for (; boxIt != boxEnd; ++boxIt) { SVGInlineBoxCharacterRange& range = *boxIt; InlineBox* curBox = range.box; ASSERT(curBox->isSVGInlineTextBox()); // Move target box if (chunk.isVerticalText) curBox->setY(curBox->y() + static_cast<int>(shift)); else curBox->setX(curBox->x() + static_cast<int>(shift)); } }
InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const LayoutPoint& point) { InlineBox* firstLeaf = firstLeafChild(); InlineBox* lastLeaf = lastLeafChild(); if (firstLeaf == lastLeaf) return firstLeaf; // FIXME: Check for vertical text! 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; }