12fc2651226baac27029e38c9d6ef883fa32084dbSteve Block/* 22fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * Copyright (C) 2011 Apple Inc. All rights reserved. 32fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 42fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * This library is free software; you can redistribute it and/or 52fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * modify it under the terms of the GNU Library General Public 62fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * License as published by the Free Software Foundation; either 72fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * version 2 of the License, or (at your option) any later version. 82fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 92fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * This library is distributed in the hope that it will be useful, 102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * but WITHOUT ANY WARRANTY; without even the implied warranty of 112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * Library General Public License for more details. 132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * You should have received a copy of the GNU Library General Public License 152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * along with this library; see the file COPYING.LIB. If not, write to 162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * Boston, MA 02110-1301, USA. 182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block */ 202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "config.h" 222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "RenderCombineText.h" 232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include "TextRun.h" 252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 262fc2651226baac27029e38c9d6ef883fa32084dbSteve Blocknamespace WebCore { 272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 282fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockconst float textCombineMargin = 1.1f; // Allow em + 10% margin 292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 302fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockRenderCombineText::RenderCombineText(Node* node, PassRefPtr<StringImpl> string) 312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block : RenderText(node, string) 322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block , m_combinedTextWidth(0) 332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block , m_isCombined(false) 342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block , m_needsFontUpdate(false) 352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 382fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid RenderCombineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 402bde8e466a4451c7319e3a072d118917957d6554Steve Block setStyleInternal(RenderStyle::clone(style())); 412fc2651226baac27029e38c9d6ef883fa32084dbSteve Block RenderText::styleDidChange(diff, oldStyle); 422fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 432fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (m_isCombined) 442fc2651226baac27029e38c9d6ef883fa32084dbSteve Block RenderText::setTextInternal(originalText()); // This RenderCombineText has been combined once. Restore the original text for the next combineText(). 452fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 462fc2651226baac27029e38c9d6ef883fa32084dbSteve Block m_needsFontUpdate = true; 472fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 482fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 492fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid RenderCombineText::setTextInternal(PassRefPtr<StringImpl> text) 502fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block RenderText::setTextInternal(text); 522fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 532fc2651226baac27029e38c9d6ef883fa32084dbSteve Block m_needsFontUpdate = true; 542fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 5681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochfloat RenderCombineText::width(unsigned from, unsigned length, const Font& font, float xPosition, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const 572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (!characters()) 592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return 0; 602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (m_isCombined) 622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return font.size(); 632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 642fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return RenderText::width(from, length, font, xPosition, fallbackFonts, glyphOverflow); 652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 6781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid RenderCombineText::adjustTextOrigin(FloatPoint& textOrigin, const FloatRect& boxRect) const 682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (m_isCombined) 702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block textOrigin.move(boxRect.height() / 2 - ceilf(m_combinedTextWidth) / 2, style()->font().pixelSize()); 712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 732fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid RenderCombineText::charactersToRender(int start, const UChar*& characters, int& length) const 742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (m_isCombined) { 762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block length = originalText()->length(); 772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block characters = originalText()->characters(); 782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return; 792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block characters = text()->characters() + start; 822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 842fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid RenderCombineText::combineText() 852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (!m_needsFontUpdate) 872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return; 882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block m_isCombined = false; 902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block m_needsFontUpdate = false; 912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // CSS3 spec says text-combine works only in vertical writing mode. 932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (style()->isHorizontalWritingMode()) 942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return; 952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block TextRun run = TextRun(String(text())); 972bde8e466a4451c7319e3a072d118917957d6554Steve Block FontDescription description = originalFont().fontDescription(); 982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block float emWidth = description.computedSize() * textCombineMargin; 992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block bool shouldUpdateFont = false; 1002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 1012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block description.setOrientation(Horizontal); // We are going to draw combined text horizontally. 1022bde8e466a4451c7319e3a072d118917957d6554Steve Block m_combinedTextWidth = originalFont().width(run); 1032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block m_isCombined = m_combinedTextWidth <= emWidth; 1042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 1052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (m_isCombined) 1062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block shouldUpdateFont = style()->setFontDescription(description); // Need to change font orientation to horizontal. 1072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block else { 1082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // Need to try compressed glyphs. 1092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block static const FontWidthVariant widthVariants[] = { HalfWidth, ThirdWidth, QuarterWidth }; 1102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block for (size_t i = 0 ; i < WTF_ARRAY_LENGTH(widthVariants) ; ++i) { 1112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block description.setWidthVariant(widthVariants[i]); 1122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block Font compressedFont = Font(description, style()->font().letterSpacing(), style()->font().wordSpacing()); 1132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block compressedFont.update(style()->font().fontSelector()); 11481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch float runWidth = compressedFont.width(run); 1152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (runWidth <= emWidth) { 1162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block m_combinedTextWidth = runWidth; 1172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block m_isCombined = true; 1182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 1192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // Replace my font with the new one. 1202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block shouldUpdateFont = style()->setFontDescription(description); 1212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block break; 1222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 1232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 1242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 1252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 1262bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!m_isCombined) 1272bde8e466a4451c7319e3a072d118917957d6554Steve Block shouldUpdateFont = style()->setFontDescription(originalFont().fontDescription()); 1282bde8e466a4451c7319e3a072d118917957d6554Steve Block 1292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (shouldUpdateFont) 1302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block style()->font().update(style()->font().fontSelector()); 1312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 1322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (m_isCombined) { 1332bde8e466a4451c7319e3a072d118917957d6554Steve Block DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&objectReplacementCharacter, 1)); 1342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block RenderText::setTextInternal(objectReplacementCharacterString.impl()); 1352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 1362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 1372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 1382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} // namespace WebCore 139