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); }
float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVerticalText, const SVGTextMetrics& metrics, float angle, float& xOrientationShift, float& yOrientationShift) const { bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(angle); // The function is based on spec requirements: // // Spec: If the 'glyph-orientation-horizontal' results in an orientation angle that is not a multiple of // of 180 degrees, then the current text position is incremented according to the vertical metrics of the glyph. // // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of // 180 degrees, then the current text position is incremented according to the horizontal metrics of the glyph. const FontMetrics& fontMetrics = m_font.fontMetrics(); float ascent = fontMetrics.floatAscent() / m_effectiveZoom; float descent = fontMetrics.floatDescent() / m_effectiveZoom; // Vertical orientation handling. if (isVerticalText) { float ascentMinusDescent = ascent - descent; if (!angle) { xOrientationShift = (ascentMinusDescent - metrics.width()) / 2; yOrientationShift = ascent; } else if (angle == 180) { xOrientationShift = (ascentMinusDescent + metrics.width()) / 2; } else if (angle == 270) { yOrientationShift = metrics.width(); xOrientationShift = ascentMinusDescent; } // Vertical advance calculation. if (angle && !orientationIsMultiplyOf180Degrees) return metrics.width(); return metrics.height(); } // Horizontal orientation handling. if (angle == 90) { yOrientationShift = -metrics.width(); } else if (angle == 180) { xOrientationShift = metrics.width(); yOrientationShift = -ascent; } else if (angle == 270) { xOrientationShift = metrics.width(); } // Horizontal advance calculation. if (angle && !orientationIsMultiplyOf180Degrees) return metrics.height(); return metrics.width(); }
bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes*& logicalAttributes, SVGTextMetrics& logicalMetrics) { const Vector<SVGTextMetrics>* textMetricsValues = &logicalAttributes->textMetricsValues(); unsigned textMetricsSize = textMetricsValues->size(); while (true) { if (m_logicalMetricsListOffset == textMetricsSize) { if (!currentLogicalCharacterAttributes(logicalAttributes)) return false; textMetricsValues = &logicalAttributes->textMetricsValues(); textMetricsSize = textMetricsValues->size(); continue; } ASSERT(textMetricsSize); ASSERT(m_logicalMetricsListOffset < textMetricsSize); logicalMetrics = textMetricsValues->at(m_logicalMetricsListOffset); if (logicalMetrics.isEmpty() || (!logicalMetrics.width() && !logicalMetrics.height())) { advanceToNextLogicalCharacter(logicalMetrics); continue; } // Stop if we found the next valid logical text metrics object. return true; } ASSERT_NOT_REACHED(); return true; }
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; }
bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGTextFragment& fragment) const { SubStringLengthData* data = static_cast<SubStringLengthData*>(queryData); int startPosition = data->startPosition; int endPosition = startPosition + data->length; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition); data->subStringLength += queryData->isVerticalText ? metrics.height() : metrics.width(); return false; }
static FloatPoint calculateGlyphPositionWithoutTransform(const QueryData* queryData, const SVGTextFragment& fragment, int offsetInFragment) { float glyphOffsetInDirection = 0; if (offsetInFragment) { SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textLayoutObject, fragment.characterOffset, offsetInFragment, queryData->textBox->direction()); if (queryData->isVerticalText) glyphOffsetInDirection = metrics.height(); else glyphOffsetInDirection = metrics.width(); } if (!queryData->textBox->isLeftToRightDirection()) { float fragmentExtent = queryData->isVerticalText ? fragment.height : fragment.width; glyphOffsetInDirection = fragmentExtent - glyphOffsetInDirection; } FloatPoint glyphPosition(fragment.x, fragment.y); if (queryData->isVerticalText) glyphPosition.move(0, glyphOffsetInDirection); else glyphPosition.move(glyphOffsetInDirection, 0); return glyphPosition; }