static inline void calculateGlyphBoundaries(const QueryData* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent) { float scalingFactor = queryData->textLineLayout.scalingFactor(); ASSERT(scalingFactor); FloatPoint glyphPosition = calculateGlyphPositionWithoutTransform(queryData, fragment, startPosition); glyphPosition.move(0, -queryData->textLineLayout.scaledFont().fontMetrics().floatAscent() / scalingFactor); extent.setLocation(glyphPosition); // Use the SVGTextMetrics computed by SVGTextMetricsBuilder (which spends // time attempting to compute more correct glyph bounds already, handling // cursive scripts to some degree.) const Vector<SVGTextMetrics>& textMetricsValues = queryData->textLineLayout.layoutAttributes()->textMetricsValues(); const SVGTextMetrics& metrics = findMetricsForCharacter(textMetricsValues, fragment, startPosition); // TODO(fs): Negative glyph extents seems kind of weird to have, but // presently it can occur in some cases (like Arabic.) FloatSize glyphSize(std::max<float>(metrics.width(), 0), std::max<float>(metrics.height(), 0)); extent.setSize(glyphSize); // If RTL, adjust the starting point to align with the LHS of the glyph bounding box. if (!queryData->textBox->isLeftToRightDirection()) { if (queryData->isVerticalText) extent.move(0, -glyphSize.height()); else extent.move(-glyphSize.width(), 0); } if (fragment.isTransformed()) { AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength); extent = fragmentTransform.mapRect(extent); } }
int SVGInlineTextBox::offsetForPositionInFragment( const SVGTextFragment& fragment, LayoutUnit position, bool includePartialGlyphs) const { LineLayoutSVGInlineText lineLayoutItem = LineLayoutSVGInlineText(this->getLineLayoutItem()); float scalingFactor = lineLayoutItem.scalingFactor(); ASSERT(scalingFactor); const ComputedStyle& style = lineLayoutItem.styleRef(); TextRun textRun = constructTextRun(style, fragment); // Eventually handle lengthAdjust="spacingAndGlyphs". // FIXME: Handle vertical text. if (fragment.isTransformed()) { AffineTransform fragmentTransform = fragment.buildFragmentTransform(); textRun.setHorizontalGlyphStretch( clampTo<float>(fragmentTransform.xScale())); } return fragment.characterOffset - start() + lineLayoutItem.scaledFont().offsetForPosition( textRun, position * scalingFactor, includePartialGlyphs); }
static FloatPoint calculateGlyphPosition(const QueryData* queryData, const SVGTextFragment& fragment, int offsetInFragment) { FloatPoint glyphPosition = calculateGlyphPositionWithoutTransform(queryData, fragment, offsetInFragment); if (fragment.isTransformed()) { AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength); glyphPosition = fragmentTransform.mapPoint(glyphPosition); } return glyphPosition; }
static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent) { float scalingFactor = queryData->textRenderer->scalingFactor(); ASSERT(scalingFactor); extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor)); if (startPosition) { SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition); if (queryData->isVerticalText) extent.move(0, metrics.height()); else extent.move(metrics.width(), 0); } SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, 1); extent.setSize(FloatSize(metrics.width(), metrics.height())); AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); if (fragmentTransform.isIdentity()) return; extent = fragmentTransform.mapRect(extent); }
bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const { EndPositionOfCharacterData* data = static_cast<EndPositionOfCharacterData*>(queryData); int startPosition = data->position; int endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; data->endPosition = FloatPoint(fragment.x, fragment.y); SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition + 1); if (queryData->isVerticalText) data->endPosition.move(0, metrics.height()); else data->endPosition.move(metrics.width(), 0); AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); if (fragmentTransform.isIdentity()) return true; data->endPosition = fragmentTransform.mapPoint(data->endPosition); return true; }
static inline FloatRect calculateFragmentBoundaries(LineLayoutSVGInlineText textLineLayout, const SVGTextFragment& fragment) { float scalingFactor = textLineLayout.scalingFactor(); ASSERT(scalingFactor); float baseline = textLineLayout.scaledFont().fontMetrics().floatAscent() / scalingFactor; return fragment.boundingBox(baseline); }
static bool rotationOfCharacterCallback(QueryData* queryData, const SVGTextFragment& fragment) { RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData); int startPosition = data->position; int endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; if (!fragment.isTransformed()) { data->rotation = 0; } else { AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength); fragmentTransform.scale(1 / fragmentTransform.xScale(), 1 / fragmentTransform.yScale()); data->rotation = narrowPrecisionToFloat(rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a()))); } return true; }
static inline FloatRect calculateFragmentBoundaries(const LayoutSVGInlineText& textLayoutObject, const SVGTextFragment& fragment) { float scalingFactor = textLayoutObject.scalingFactor(); ASSERT(scalingFactor); float baseline = textLayoutObject.scaledFont().fontMetrics().floatAscent() / scalingFactor; AffineTransform fragmentTransform; FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); return fragmentTransform.mapRect(fragmentRect); }
int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragment, float position, bool includePartialGlyphs) const { float scalingFactor = renderer().scalingFactor(); ASSERT(scalingFactor); TextRun textRun = constructTextRun(&renderer().style(), fragment); // Eventually handle lengthAdjust="spacingAndGlyphs". // FIXME: Handle vertical text. AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragmentTransform.xScale())); return fragment.characterOffset - start() + renderer().scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); }
bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const { RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData); unsigned startPosition = data->position; unsigned endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); if (fragmentTransform.isIdentity()) data->rotation = 0; else { fragmentTransform.scale(1 / fragmentTransform.xScale(), 1 / fragmentTransform.yScale()); data->rotation = narrowPrecisionToFloat(rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a()))); } return true; }
int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragment, FloatWillBeLayoutUnit position, bool includePartialGlyphs) const { LayoutSVGInlineText& textLayoutObject = toLayoutSVGInlineText(this->layoutObject()); float scalingFactor = textLayoutObject.scalingFactor(); ASSERT(scalingFactor); const ComputedStyle& style = textLayoutObject.styleRef(); TextRun textRun = constructTextRun(style, fragment); // Eventually handle lengthAdjust="spacingAndGlyphs". // FIXME: Handle vertical text. AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragmentTransform.xScale())); return fragment.characterOffset - start() + textLayoutObject.scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); }