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 "RenderCombineText.h" 23 24#include "RenderBlock.h" 25#include "StyleInheritedData.h" 26 27namespace WebCore { 28 29const float textCombineMargin = 1.15f; // Allow em + 15% margin 30 31RenderCombineText::RenderCombineText(Text& textNode, PassRefPtr<StringImpl> string) 32 : RenderText(textNode, string) 33 , m_combinedTextWidth(0) 34 , m_isCombined(false) 35 , m_needsFontUpdate(false) 36{ 37} 38 39void RenderCombineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 40{ 41 // FIXME: This is pretty hackish. 42 m_combineFontStyle = RenderStyle::clone(&style()); 43 44 RenderText::styleDidChange(diff, oldStyle); 45 46 if (m_isCombined) { 47 RenderText::setRenderedText(originalText()); // This RenderCombineText has been combined once. Restore the original text for the next combineText(). 48 m_isCombined = false; 49 } 50 51 m_needsFontUpdate = true; 52} 53 54void RenderCombineText::setRenderedText(const String& text) 55{ 56 RenderText::setRenderedText(text); 57 58 m_needsFontUpdate = true; 59} 60 61float RenderCombineText::width(unsigned from, unsigned length, const Font& font, float xPosition, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 62{ 63 if (m_isCombined) 64 return font.size(); 65 66 return RenderText::width(from, length, font, xPosition, fallbackFonts, glyphOverflow); 67} 68 69void RenderCombineText::adjustTextOrigin(FloatPoint& textOrigin, const FloatRect& boxRect) const 70{ 71 if (m_isCombined) 72 textOrigin.move(boxRect.height() / 2 - ceilf(m_combinedTextWidth) / 2, style().font().pixelSize()); 73} 74 75void RenderCombineText::getStringToRender(int start, String& string, int& length) const 76{ 77 ASSERT(start >= 0); 78 if (m_isCombined) { 79 string = originalText(); 80 length = string.length(); 81 return; 82 } 83 84 string = text(); 85 string = string.substringSharingImpl(static_cast<unsigned>(start), length); 86} 87 88void RenderCombineText::combineText() 89{ 90 if (!m_needsFontUpdate) 91 return; 92 93 m_isCombined = false; 94 m_needsFontUpdate = false; 95 96 // CSS3 spec says text-combine works only in vertical writing mode. 97 if (style().isHorizontalWritingMode()) 98 return; 99 100 TextRun run = RenderBlock::constructTextRun(this, originalFont(), this, style()); 101 FontDescription description = originalFont().fontDescription(); 102 float emWidth = description.computedSize() * textCombineMargin; 103 bool shouldUpdateFont = false; 104 105 description.setOrientation(Horizontal); // We are going to draw combined text horizontally. 106 m_combinedTextWidth = originalFont().width(run); 107 m_isCombined = m_combinedTextWidth <= emWidth; 108 109 FontSelector* fontSelector = style().font().fontSelector(); 110 111 if (m_isCombined) 112 shouldUpdateFont = m_combineFontStyle->setFontDescription(description); // Need to change font orientation to horizontal. 113 else { 114 // Need to try compressed glyphs. 115 static const FontWidthVariant widthVariants[] = { HalfWidth, ThirdWidth, QuarterWidth }; 116 for (size_t i = 0 ; i < WTF_ARRAY_LENGTH(widthVariants) ; ++i) { 117 description.setWidthVariant(widthVariants[i]); 118 Font compressedFont = Font(description, style().font().letterSpacing(), style().font().wordSpacing()); 119 compressedFont.update(fontSelector); 120 float runWidth = compressedFont.width(run); 121 if (runWidth <= emWidth) { 122 m_combinedTextWidth = runWidth; 123 m_isCombined = true; 124 125 // Replace my font with the new one. 126 shouldUpdateFont = m_combineFontStyle->setFontDescription(description); 127 break; 128 } 129 } 130 } 131 132 if (!m_isCombined) 133 shouldUpdateFont = m_combineFontStyle->setFontDescription(originalFont().fontDescription()); 134 135 if (shouldUpdateFont) 136 m_combineFontStyle->font().update(fontSelector); 137 138 if (m_isCombined) { 139 DEPRECATED_DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&objectReplacementCharacter, 1)); 140 RenderText::setRenderedText(objectReplacementCharacterString.impl()); 141 } 142} 143 144} // namespace WebCore 145