1 /* 2 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21 #include "config.h" 22 #include "core/rendering/RenderCombineText.h" 23 24 #include "core/rendering/TextRunConstructor.h" 25 26 namespace blink { 27 28 const float textCombineMargin = 1.1f; // Allow em + 10% margin 29 30 RenderCombineText::RenderCombineText(Node* node, PassRefPtr<StringImpl> string) 31 : RenderText(node, string) 32 , m_combinedTextWidth(0) 33 , m_isCombined(false) 34 , m_needsFontUpdate(false) 35 { 36 } 37 38 void RenderCombineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 39 { 40 setStyleInternal(RenderStyle::clone(style())); 41 RenderText::styleDidChange(diff, oldStyle); 42 43 if (m_isCombined) { 44 RenderText::setTextInternal(originalText()); // This RenderCombineText has been combined once. Restore the original text for the next combineText(). 45 m_isCombined = false; 46 } 47 48 m_needsFontUpdate = true; 49 } 50 51 void RenderCombineText::setTextInternal(PassRefPtr<StringImpl> text) 52 { 53 RenderText::setTextInternal(text); 54 55 m_needsFontUpdate = true; 56 } 57 58 float RenderCombineText::width(unsigned from, unsigned length, const Font& font, float xPosition, TextDirection direction, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 59 { 60 if (!length) 61 return 0; 62 63 if (hasEmptyText()) 64 return 0; 65 66 if (m_isCombined) 67 return font.fontDescription().computedSize(); 68 69 return RenderText::width(from, length, font, xPosition, direction, fallbackFonts, glyphOverflow); 70 } 71 72 void RenderCombineText::adjustTextOrigin(FloatPoint& textOrigin, const FloatRect& boxRect) const 73 { 74 if (m_isCombined) 75 textOrigin.move(boxRect.height() / 2 - ceilf(m_combinedTextWidth) / 2, style()->font().fontDescription().computedPixelSize()); 76 } 77 78 void RenderCombineText::getStringToRender(int start, StringView& string, int& length) const 79 { 80 ASSERT(start >= 0); 81 if (m_isCombined) { 82 string = StringView(m_renderingText.impl()); 83 length = string.length(); 84 return; 85 } 86 87 string = text().createView(start, length); 88 } 89 90 void RenderCombineText::combineText() 91 { 92 if (!m_needsFontUpdate) 93 return; 94 95 m_isCombined = false; 96 m_needsFontUpdate = false; 97 98 // CSS3 spec says text-combine works only in vertical writing mode. 99 if (style()->isHorizontalWritingMode()) 100 return; 101 102 TextRun run = constructTextRun(this, originalFont(), this, style(), style()->direction()); 103 FontDescription description = originalFont().fontDescription(); 104 float emWidth = description.computedSize() * textCombineMargin; 105 bool shouldUpdateFont = false; 106 107 description.setOrientation(Horizontal); // We are going to draw combined text horizontally. 108 m_combinedTextWidth = originalFont().width(run); 109 m_isCombined = m_combinedTextWidth <= emWidth; 110 111 FontSelector* fontSelector = style()->font().fontSelector(); 112 113 if (m_isCombined) 114 shouldUpdateFont = style()->setFontDescription(description); // Need to change font orientation to horizontal. 115 else { 116 // Need to try compressed glyphs. 117 static const FontWidthVariant widthVariants[] = { HalfWidth, ThirdWidth, QuarterWidth }; 118 for (size_t i = 0 ; i < WTF_ARRAY_LENGTH(widthVariants) ; ++i) { 119 description.setWidthVariant(widthVariants[i]); 120 Font compressedFont = Font(description); 121 compressedFont.update(fontSelector); 122 float runWidth = compressedFont.width(run); 123 if (runWidth <= emWidth) { 124 m_combinedTextWidth = runWidth; 125 m_isCombined = true; 126 127 // Replace my font with the new one. 128 shouldUpdateFont = style()->setFontDescription(description); 129 break; 130 } 131 } 132 } 133 134 if (!m_isCombined) 135 shouldUpdateFont = style()->setFontDescription(originalFont().fontDescription()); 136 137 if (shouldUpdateFont) 138 style()->font().update(fontSelector); 139 140 if (m_isCombined) { 141 DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&objectReplacementCharacter, 1)); 142 m_renderingText = text(); 143 RenderText::setTextInternal(objectReplacementCharacterString.impl()); 144 } 145 } 146 147 } // namespace blink 148