PositionWithAffinity LayoutSVGInlineText::positionForPoint(const LayoutPoint& point) { if (!firstTextBox() || !textLength()) return createPositionWithAffinity(0, DOWNSTREAM); ASSERT(m_scalingFactor); float baseline = m_scaledFont.fontMetrics().floatAscent() / m_scalingFactor; LayoutBlock* containingBlock = this->containingBlock(); ASSERT(containingBlock); // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates. FloatPoint absolutePoint(point); absolutePoint.moveBy(containingBlock->location()); float closestDistance = std::numeric_limits<float>::max(); float closestDistancePosition = 0; const SVGTextFragment* closestDistanceFragment = 0; SVGInlineTextBox* closestDistanceBox = 0; AffineTransform fragmentTransform; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { if (!box->isSVGInlineTextBox()) continue; SVGInlineTextBox* textBox = toSVGInlineTextBox(box); Vector<SVGTextFragment>& fragments = textBox->textFragments(); unsigned textFragmentsSize = fragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { const SVGTextFragment& fragment = fragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentRect = fragmentTransform.mapRect(fragmentRect); float distance = 0; if (!fragmentRect.contains(absolutePoint)) distance = squaredDistanceToClosestPoint(fragmentRect, absolutePoint); if (distance <= closestDistance) { closestDistance = distance; closestDistanceBox = textBox; closestDistanceFragment = &fragment; closestDistancePosition = fragmentRect.x(); } } } if (!closestDistanceFragment) return createPositionWithAffinity(0, DOWNSTREAM); int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true); return createPositionWithAffinity(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM); }
void BlockPainter::paintContinuationOutlines(const PaintInfo& info, const LayoutPoint& paintOffset) { LayoutInline* inlineCont = m_layoutBlock.inlineElementContinuation(); if (inlineCont && inlineCont->style()->hasOutline() && inlineCont->style()->visibility() == VISIBLE) { LayoutInline* inlineLayoutObject = toLayoutInline(inlineCont->node()->layoutObject()); LayoutBlock* cb = m_layoutBlock.containingBlock(); bool inlineEnclosedInSelfPaintingLayer = false; for (LayoutBoxModelObject* box = inlineLayoutObject; box != cb; box = box->parent()->enclosingBoxModelObject()) { if (box->hasSelfPaintingLayer()) { inlineEnclosedInSelfPaintingLayer = true; break; } } // Do not add continuations for outline painting by our containing block if we are a relative positioned // anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on layoutObjects in its continuation table being // in the same layer. if (!inlineEnclosedInSelfPaintingLayer && !m_layoutBlock.hasLayer()) { cb->addContinuationWithOutline(inlineLayoutObject); } else if (!inlineLayoutObject->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && m_layoutBlock.hasLayer())) { // The outline might be painted multiple times if multiple blocks have the same inline element continuation, and the inline has a self-painting layer. ScopeRecorder scopeRecorder(*info.context); InlinePainter(*inlineLayoutObject).paintOutline(info, paintOffset - m_layoutBlock.locationOffset() + inlineLayoutObject->containingBlock()->location()); } } ContinuationOutlineTableMap* table = continuationOutlineTable(); if (table->isEmpty()) return; OwnPtr<ListHashSet<LayoutInline*>> continuations = table->take(&m_layoutBlock); if (!continuations) return; LayoutPoint accumulatedPaintOffset = paintOffset; // Paint each continuation outline. ListHashSet<LayoutInline*>::iterator end = continuations->end(); for (ListHashSet<LayoutInline*>::iterator it = continuations->begin(); it != end; ++it) { // Need to add in the coordinates of the intervening blocks. LayoutInline* flow = *it; LayoutBlock* block = flow->containingBlock(); for ( ; block && block != &m_layoutBlock; block = block->containingBlock()) accumulatedPaintOffset.moveBy(block->location()); ASSERT(block); InlinePainter(*flow).paintOutline(info, accumulatedPaintOffset); } }
PositionWithAffinity LayoutSVGInlineText::positionForPoint(const LayoutPoint& point) { if (!hasTextBoxes() || !textLength()) return createPositionWithAffinity(0); ASSERT(m_scalingFactor); float baseline = m_scaledFont.getFontMetrics().floatAscent() / m_scalingFactor; LayoutBlock* containingBlock = this->containingBlock(); ASSERT(containingBlock); // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates. FloatPoint absolutePoint(point); absolutePoint.moveBy(containingBlock->location()); float closestDistance = std::numeric_limits<float>::max(); float closestDistancePosition = 0; const SVGTextFragment* closestDistanceFragment = nullptr; SVGInlineTextBox* closestDistanceBox = nullptr; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { if (!box->isSVGInlineTextBox()) continue; SVGInlineTextBox* textBox = toSVGInlineTextBox(box); for (const SVGTextFragment& fragment : textBox->textFragments()) { FloatRect fragmentRect = fragment.boundingBox(baseline); float distance = 0; if (!fragmentRect.contains(absolutePoint)) distance = fragmentRect.squaredDistanceTo(absolutePoint); if (distance <= closestDistance) { closestDistance = distance; closestDistanceBox = textBox; closestDistanceFragment = &fragment; closestDistancePosition = fragmentRect.x(); } } } if (!closestDistanceFragment) return createPositionWithAffinity(0); int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, LayoutUnit(absolutePoint.x() - closestDistancePosition), true); return createPositionWithAffinity(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : TextAffinity::Downstream); }