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