void RenderCombineText::combineText() { if (!m_needsFontUpdate) return; m_isCombined = false; m_needsFontUpdate = false; // CSS3 spec says text-combine works only in vertical writing mode. if (style().isHorizontalWritingMode()) return; auto description = originalFont().fontDescription(); float emWidth = description.computedSize() * textCombineMargin; bool shouldUpdateFont = false; description.setOrientation(Horizontal); // We are going to draw combined text horizontally. GlyphOverflow glyphOverflow; glyphOverflow.computeBounds = true; float combinedTextWidth = width(0, textLength(), originalFont(), 0, nullptr, &glyphOverflow); m_isCombined = combinedTextWidth <= emWidth; FontSelector* fontSelector = style().fontCascade().fontSelector(); if (m_isCombined) shouldUpdateFont = m_combineFontStyle->setFontDescription(description); // Need to change font orientation to horizontal. else { // Need to try compressed glyphs. static const FontWidthVariant widthVariants[] = { HalfWidth, ThirdWidth, QuarterWidth }; for (size_t i = 0 ; i < WTF_ARRAY_LENGTH(widthVariants) ; ++i) { description.setWidthVariant(widthVariants[i]); // When modifying this, make sure to keep it in sync with FontPlatformData::isForTextCombine()! FontCascade compressedFont(description, style().fontCascade().letterSpacing(), style().fontCascade().wordSpacing()); compressedFont.update(fontSelector); float runWidth = RenderText::width(0, textLength(), compressedFont, 0, nullptr, &glyphOverflow); if (runWidth <= emWidth) { combinedTextWidth = runWidth; m_isCombined = true; // Replace my font with the new one. shouldUpdateFont = m_combineFontStyle->setFontDescription(description); break; } } } if (!m_isCombined) shouldUpdateFont = m_combineFontStyle->setFontDescription(originalFont().fontDescription()); if (shouldUpdateFont) m_combineFontStyle->fontCascade().update(fontSelector); if (m_isCombined) { DEPRECATED_DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&objectReplacementCharacter, 1)); RenderText::setRenderedText(objectReplacementCharacterString.impl()); m_combinedTextSize = FloatSize(combinedTextWidth, glyphOverflow.bottom + glyphOverflow.top); } }
void RenderCombineText::combineText() { if (!m_needsFontUpdate) return; // An ancestor element may trigger us to lay out again, even when we're already combined. if (m_isCombined) RenderText::setRenderedText(originalText()); m_isCombined = false; m_needsFontUpdate = false; // CSS3 spec says text-combine works only in vertical writing mode. if (style().isHorizontalWritingMode()) return; auto description = originalFont().fontDescription(); float emWidth = description.computedSize() * textCombineMargin; bool shouldUpdateFont = false; description.setOrientation(Horizontal); // We are going to draw combined text horizontally. GlyphOverflow glyphOverflow; glyphOverflow.computeBounds = true; float combinedTextWidth = width(0, textLength(), originalFont(), 0, nullptr, &glyphOverflow); float bestFitDelta = combinedTextWidth - emWidth; auto bestFitDescription = description; m_isCombined = combinedTextWidth <= emWidth; FontSelector* fontSelector = style().fontCascade().fontSelector(); if (m_isCombined) shouldUpdateFont = m_combineFontStyle->setFontDescription(description); // Need to change font orientation to horizontal. else { // Need to try compressed glyphs. static const FontWidthVariant widthVariants[] = { HalfWidth, ThirdWidth, QuarterWidth }; for (size_t i = 0 ; i < WTF_ARRAY_LENGTH(widthVariants) ; ++i) { description.setWidthVariant(widthVariants[i]); // When modifying this, make sure to keep it in sync with FontPlatformData::isForTextCombine()! FontCascade compressedFont(description, style().fontCascade().letterSpacing(), style().fontCascade().wordSpacing()); compressedFont.update(fontSelector); glyphOverflow.left = glyphOverflow.top = glyphOverflow.right = glyphOverflow.bottom = 0; float runWidth = RenderText::width(0, textLength(), compressedFont, 0, nullptr, &glyphOverflow); if (runWidth <= emWidth) { combinedTextWidth = runWidth; m_isCombined = true; // Replace my font with the new one. shouldUpdateFont = m_combineFontStyle->setFontDescription(description); break; } float widthDelta = runWidth - emWidth; if (widthDelta < bestFitDelta) { bestFitDelta = widthDelta; bestFitDescription = description; } } } if (!m_isCombined) { float scaleFactor = std::max(0.4f, emWidth / (emWidth + bestFitDelta)); float originalSize = bestFitDescription.computedSize(); do { float computedSize = originalSize * scaleFactor; bestFitDescription.setComputedSize(computedSize); shouldUpdateFont = m_combineFontStyle->setFontDescription(bestFitDescription); FontCascade compressedFont(bestFitDescription, style().fontCascade().letterSpacing(), style().fontCascade().wordSpacing()); compressedFont.update(fontSelector); glyphOverflow.left = glyphOverflow.top = glyphOverflow.right = glyphOverflow.bottom = 0; float runWidth = RenderText::width(0, textLength(), compressedFont, 0, nullptr, &glyphOverflow); if (runWidth <= emWidth) { combinedTextWidth = runWidth; m_isCombined = true; break; } scaleFactor -= 0.05f; } while (scaleFactor >= 0.4f); } if (shouldUpdateFont) m_combineFontStyle->fontCascade().update(fontSelector); if (m_isCombined) { static NeverDestroyed<String> objectReplacementCharacterString(&objectReplacementCharacter, 1); RenderText::setRenderedText(objectReplacementCharacterString.get()); m_combinedTextWidth = combinedTextWidth; m_combinedTextAscent = glyphOverflow.top; m_combinedTextDescent = glyphOverflow.bottom; } }