15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2011 Apple Inc. All rights reserved. 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is free software; you can redistribute it and/or 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modify it under the terms of the GNU Library General Public 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License as published by the Free Software Foundation; either 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version 2 of the License, or (at your option) any later version. 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is distributed in the hope that it will be useful, 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Library General Public License for more details. 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * You should have received a copy of the GNU Library General Public License 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * along with this library; see the file COPYING.LIB. If not, write to 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Boston, MA 02110-1301, USA. 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 2253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderCombineText.h" 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#include "core/rendering/RenderBlockFlow.h" 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore { 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const float textCombineMargin = 1.1f; // Allow em + 10% margin 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RenderCombineText::RenderCombineText(Node* node, PassRefPtr<StringImpl> string) 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : RenderText(node, string) 325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_combinedTextWidth(0) 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_isCombined(false) 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_needsFontUpdate(false) 355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderCombineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) setStyleInternal(RenderStyle::clone(style())); 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderText::styleDidChange(diff, oldStyle); 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_isCombined) { 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderText::setTextInternal(originalText()); // This RenderCombineText has been combined once. Restore the original text for the next combineText(). 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_isCombined = false; 465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_needsFontUpdate = true; 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderCombineText::setTextInternal(PassRefPtr<StringImpl> text) 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderText::setTextInternal(text); 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_needsFontUpdate = true; 565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float RenderCombineText::width(unsigned from, unsigned length, const Font& font, float xPosition, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 600019e4eead4d990e4304c54a9028aca9122fb256Ben Murdoch if (hasEmptyText()) 615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_isCombined) 645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return font.size(); 655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return RenderText::width(from, length, font, xPosition, fallbackFonts, glyphOverflow); 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderCombineText::adjustTextOrigin(FloatPoint& textOrigin, const FloatRect& boxRect) const 705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_isCombined) 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) textOrigin.move(boxRect.height() / 2 - ceilf(m_combinedTextWidth) / 2, style()->font().pixelSize()); 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochvoid RenderCombineText::getStringToRender(int start, StringView& string, int& length) const 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(start >= 0); 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_isCombined) { 797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch string = StringView(originalText()); 805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) length = string.length(); 815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch string = text().createView(start, length); 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderCombineText::combineText() 885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_needsFontUpdate) 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_isCombined = false; 935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_needsFontUpdate = false; 945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // CSS3 spec says text-combine works only in vertical writing mode. 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (style()->isHorizontalWritingMode()) 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) TextRun run = RenderBlockFlow::constructTextRun(this, originalFont(), this, style()); 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FontDescription description = originalFont().fontDescription(); 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float emWidth = description.computedSize() * textCombineMargin; 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool shouldUpdateFont = false; 1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) description.setOrientation(Horizontal); // We are going to draw combined text horizontally. 1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_combinedTextWidth = originalFont().width(run); 1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_isCombined = m_combinedTextWidth <= emWidth; 1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FontSelector* fontSelector = style()->font().fontSelector(); 1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_isCombined) 1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) shouldUpdateFont = style()->setFontDescription(description); // Need to change font orientation to horizontal. 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else { 1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Need to try compressed glyphs. 1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) static const FontWidthVariant widthVariants[] = { HalfWidth, ThirdWidth, QuarterWidth }; 1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0 ; i < WTF_ARRAY_LENGTH(widthVariants) ; ++i) { 1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) description.setWidthVariant(widthVariants[i]); 1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Font compressedFont = Font(description, style()->font().letterSpacing(), style()->font().wordSpacing()); 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) compressedFont.update(fontSelector); 1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float runWidth = compressedFont.width(run); 1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (runWidth <= emWidth) { 1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_combinedTextWidth = runWidth; 1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_isCombined = true; 1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Replace my font with the new one. 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) shouldUpdateFont = style()->setFontDescription(description); 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_isCombined) 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) shouldUpdateFont = style()->setFontDescription(originalFont().fontDescription()); 1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldUpdateFont) 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) style()->font().update(fontSelector); 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_isCombined) { 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&objectReplacementCharacter, 1)); 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RenderText::setTextInternal(objectReplacementCharacterString.impl()); 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace WebCore 144