Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2000 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  *
     22  */
     23 
     24 #include "config.h"
     25 #include "Font.h"
     26 
     27 #include "FloatRect.h"
     28 #include "FontCache.h"
     29 #include "FontTranscoder.h"
     30 #include "IntPoint.h"
     31 #include "GlyphBuffer.h"
     32 #include "TextRun.h"
     33 #include "WidthIterator.h"
     34 #include <wtf/MathExtras.h>
     35 #include <wtf/UnusedParam.h>
     36 
     37 using namespace WTF;
     38 using namespace Unicode;
     39 
     40 namespace WebCore {
     41 
     42 Font::CodePath Font::s_codePath = Auto;
     43 
     44 // ============================================================================================
     45 // Font Implementation (Cross-Platform Portion)
     46 // ============================================================================================
     47 
     48 Font::Font()
     49     : m_letterSpacing(0)
     50     , m_wordSpacing(0)
     51     , m_isPlatformFont(false)
     52     , m_needsTranscoding(false)
     53 {
     54 }
     55 
     56 Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
     57     : m_fontDescription(fd)
     58     , m_letterSpacing(letterSpacing)
     59     , m_wordSpacing(wordSpacing)
     60     , m_isPlatformFont(false)
     61     , m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
     62 {
     63 }
     64 
     65 Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
     66     : m_fontList(FontFallbackList::create())
     67     , m_letterSpacing(0)
     68     , m_wordSpacing(0)
     69     , m_isPlatformFont(true)
     70 {
     71     m_fontDescription.setUsePrinterFont(isPrinterFont);
     72     m_fontDescription.setFontSmoothing(fontSmoothingMode);
     73     m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
     74     m_fontList->setPlatformFont(fontData);
     75 }
     76 
     77 Font::Font(const Font& other)
     78     : m_fontDescription(other.m_fontDescription)
     79     , m_fontList(other.m_fontList)
     80     , m_letterSpacing(other.m_letterSpacing)
     81     , m_wordSpacing(other.m_wordSpacing)
     82     , m_isPlatformFont(other.m_isPlatformFont)
     83     , m_needsTranscoding(fontTranscoder().needsTranscoding(other.m_fontDescription))
     84 {
     85 }
     86 
     87 Font& Font::operator=(const Font& other)
     88 {
     89     m_fontDescription = other.m_fontDescription;
     90     m_fontList = other.m_fontList;
     91     m_letterSpacing = other.m_letterSpacing;
     92     m_wordSpacing = other.m_wordSpacing;
     93     m_isPlatformFont = other.m_isPlatformFont;
     94     m_needsTranscoding = other.m_needsTranscoding;
     95     return *this;
     96 }
     97 
     98 bool Font::operator==(const Font& other) const
     99 {
    100     // Our FontData don't have to be checked, since checking the font description will be fine.
    101     // FIXME: This does not work if the font was made with the FontPlatformData constructor.
    102     if (loadingCustomFonts() || other.loadingCustomFonts())
    103         return false;
    104 
    105     FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
    106     FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
    107 
    108     return first == second
    109            && m_fontDescription == other.m_fontDescription
    110            && m_letterSpacing == other.m_letterSpacing
    111            && m_wordSpacing == other.m_wordSpacing
    112            && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
    113 }
    114 
    115 void Font::update(PassRefPtr<FontSelector> fontSelector) const
    116 {
    117     // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
    118     // being reasonably safe (because inherited fonts in the render tree pick up the new
    119     // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
    120     // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
    121     // and could eventually be rectified by using RefPtrs for Fonts themselves.
    122     if (!m_fontList)
    123         m_fontList = FontFallbackList::create();
    124     m_fontList->invalidate(fontSelector);
    125 }
    126 
    127 void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
    128 {
    129     // Don't draw anything while we are using custom fonts that are in the process of loading.
    130     if (loadingCustomFonts())
    131         return;
    132 
    133     to = (to == -1 ? run.length() : to);
    134 
    135 #if ENABLE(SVG_FONTS)
    136     if (primaryFont()->isSVGFont()) {
    137         drawTextUsingSVGFont(context, run, point, from, to);
    138         return;
    139     }
    140 #endif
    141 
    142     if (codePath(run) != Complex)
    143         return drawSimpleText(context, run, point, from, to);
    144 
    145     return drawComplexText(context, run, point, from, to);
    146 }
    147 
    148 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
    149 {
    150     if (loadingCustomFonts())
    151         return;
    152 
    153     if (to < 0)
    154         to = run.length();
    155 
    156 #if ENABLE(SVG_FONTS)
    157     // FIXME: Implement for SVG fonts.
    158     if (primaryFont()->isSVGFont())
    159         return;
    160 #endif
    161 
    162     if (codePath(run) != Complex)
    163         drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
    164     else
    165         drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
    166 }
    167 
    168 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
    169 {
    170 #if ENABLE(SVG_FONTS)
    171     if (primaryFont()->isSVGFont())
    172         return floatWidthUsingSVGFont(run);
    173 #endif
    174 
    175     CodePath codePathToUse = codePath(run);
    176     if (codePathToUse != Complex) {
    177         // If the complex text implementation cannot return fallback fonts, avoid
    178         // returning them for simple text as well.
    179         static bool returnFallbackFonts = canReturnFallbackFontsForComplexText();
    180         return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow || (glyphOverflow && glyphOverflow->computeBounds) ? glyphOverflow : 0);
    181     }
    182 
    183     return floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
    184 }
    185 
    186 float Font::width(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
    187 {
    188 #if !ENABLE(SVG_FONTS)
    189     UNUSED_PARAM(extraCharsAvailable);
    190 #else
    191     if (primaryFont()->isSVGFont())
    192         return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName);
    193 #endif
    194 
    195     charsConsumed = run.length();
    196     glyphName = "";
    197 
    198     if (codePath(run) != Complex)
    199         return floatWidthForSimpleText(run, 0);
    200 
    201     return floatWidthForComplexText(run);
    202 }
    203 
    204 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
    205 {
    206 #if ENABLE(SVG_FONTS)
    207     if (primaryFont()->isSVGFont())
    208         return selectionRectForTextUsingSVGFont(run, point, h, from, to);
    209 #endif
    210 
    211     to = (to == -1 ? run.length() : to);
    212 
    213     if (codePath(run) != Complex)
    214         return selectionRectForSimpleText(run, point, h, from, to);
    215 
    216     return selectionRectForComplexText(run, point, h, from, to);
    217 }
    218 
    219 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
    220 {
    221 #if ENABLE(SVG_FONTS)
    222     if (primaryFont()->isSVGFont())
    223         return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
    224 #endif
    225 
    226     if (codePath(run) != Complex)
    227         return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
    228 
    229     return offsetForPositionForComplexText(run, x, includePartialGlyphs);
    230 }
    231 
    232 #if ENABLE(SVG_FONTS)
    233 bool Font::isSVGFont() const
    234 {
    235     return primaryFont()->isSVGFont();
    236 }
    237 #endif
    238 
    239 String Font::normalizeSpaces(const UChar* characters, unsigned length)
    240 {
    241     UChar* buffer;
    242     String normalized = String::createUninitialized(length, buffer);
    243 
    244     for (unsigned i = 0; i < length; ++i)
    245         buffer[i] = normalizeSpaces(characters[i]);
    246 
    247     return normalized;
    248 }
    249 
    250 static bool shouldUseFontSmoothing = true;
    251 
    252 void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
    253 {
    254     ASSERT(isMainThread());
    255     shouldUseFontSmoothing = shouldUseSmoothing;
    256 }
    257 
    258 bool Font::shouldUseSmoothing()
    259 {
    260     return shouldUseFontSmoothing;
    261 }
    262 
    263 void Font::setCodePath(CodePath p)
    264 {
    265     s_codePath = p;
    266 }
    267 
    268 Font::CodePath Font::codePath()
    269 {
    270     return s_codePath;
    271 }
    272 
    273 Font::CodePath Font::codePath(const TextRun& run) const
    274 {
    275     if (s_codePath != Auto)
    276         return s_codePath;
    277 
    278 #if PLATFORM(QT)
    279     if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
    280         return Complex;
    281 #endif
    282 
    283     CodePath result = Simple;
    284 
    285     // Start from 0 since drawing and highlighting also measure the characters before run->from
    286     for (int i = 0; i < run.length(); i++) {
    287         const UChar c = run[i];
    288         if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
    289             continue;
    290         if (c <= 0x36F)
    291             return Complex;
    292 
    293         if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
    294             continue;
    295         if (c <= 0x05CF)
    296             return Complex;
    297 
    298         if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
    299             continue;
    300         if (c <= 0x1059)
    301             return Complex;
    302 
    303         if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
    304             continue;
    305         if (c <= 0x11FF)
    306             return Complex;
    307 
    308         if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
    309             continue;
    310         if (c <= 0x18AF)
    311             return Complex;
    312 
    313         if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
    314             continue;
    315         if (c <= 0x194F)
    316             return Complex;
    317 
    318         if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics
    319             continue;
    320         if (c <= 0x2000) {
    321             result = SimpleWithGlyphOverflow;
    322             continue;
    323         }
    324 
    325         if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
    326             continue;
    327         if (c <= 0x20FF)
    328             return Complex;
    329 
    330         if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
    331             continue;
    332         if (c <= 0xFE2F)
    333             return Complex;
    334     }
    335 
    336     if (typesettingFeatures())
    337         return Complex;
    338 
    339     return result;
    340 }
    341 
    342 bool Font::isCJKIdeograph(UChar32 c)
    343 {
    344     // The basic CJK Unified Ideographs block.
    345     if (c >= 0x4E00 && c <= 0x9FFF)
    346         return true;
    347 
    348     // CJK Unified Ideographs Extension A.
    349     if (c >= 0x3400 && c <= 0x4DBF)
    350         return true;
    351 
    352     // CJK Radicals Supplement.
    353     if (c >= 0x2E80 && c <= 0x2EFF)
    354         return true;
    355 
    356     // Kangxi Radicals.
    357     if (c >= 0x2F00 && c <= 0x2FDF)
    358         return true;
    359 
    360     // CJK Strokes.
    361     if (c >= 0x31C0 && c <= 0x31EF)
    362         return true;
    363 
    364     // CJK Compatibility Ideographs.
    365     if (c >= 0xF900 && c <= 0xFAFF)
    366         return true;
    367 
    368     // CJK Unified Ideographs Extension B.
    369     if (c >= 0x20000 && c <= 0x2A6DF)
    370         return true;
    371 
    372     // CJK Unified Ideographs Extension C.
    373     if (c >= 0x2A700 && c <= 0x2B73F)
    374         return true;
    375 
    376     // CJK Unified Ideographs Extension D.
    377     if (c >= 0x2B740 && c <= 0x2B81F)
    378         return true;
    379 
    380     // CJK Compatibility Ideographs Supplement.
    381     if (c >= 0x2F800 && c <= 0x2FA1F)
    382         return true;
    383 
    384     return false;
    385 }
    386 
    387 bool Font::isCJKIdeographOrSymbol(UChar32 c)
    388 {
    389     // 0x2C7 Caron, Mandarin Chinese 3rd Tone
    390     // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
    391     // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
    392     // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
    393     if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
    394         return true;
    395 
    396     // Ideographic Description Characters.
    397     if (c >= 0x2FF0 && c <= 0x2FFF)
    398         return true;
    399 
    400     // CJK Symbols and Punctuation.
    401     if (c >= 0x3000 && c <= 0x303F)
    402         return true;
    403 
    404     // Hiragana
    405     if (c >= 0x3040 && c <= 0x309F)
    406         return true;
    407 
    408     // Katakana
    409     if (c >= 0x30A0 && c <= 0x30FF)
    410         return true;
    411 
    412     // Bopomofo
    413     if (c >= 0x3100 && c <= 0x312F)
    414         return true;
    415 
    416     // Bopomofo Extended
    417     if (c >= 0x31A0 && c <= 0x31BF)
    418         return true;
    419 
    420     // Enclosed CJK Letters and Months.
    421     if (c >= 0x3200 && c <= 0x32FF)
    422         return true;
    423 
    424     // CJK Compatibility.
    425     if (c >= 0x3300 && c <= 0x33FF)
    426         return true;
    427 
    428     // CJK Compatibility Forms.
    429     if (c >= 0xFE30 && c <= 0xFE4F)
    430         return true;
    431 
    432     // Halfwidth and Fullwidth Forms
    433     // Usually only used in CJK
    434     if (c >= 0xFF00 && c <= 0xFFEF)
    435         return true;
    436 
    437     // Emoji.
    438     if (c >= 0x1F200 && c <= 0x1F6F)
    439         return true;
    440 
    441     return isCJKIdeograph(c);
    442 }
    443 
    444 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
    445 {
    446     static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
    447     unsigned count = 0;
    448     if (direction == LTR) {
    449         for (size_t i = 0; i < length; ++i) {
    450             UChar32 character = characters[i];
    451             if (treatAsSpace(character)) {
    452                 count++;
    453                 isAfterExpansion = true;
    454                 continue;
    455             }
    456             if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
    457                 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
    458                 i++;
    459             }
    460             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
    461                 if (!isAfterExpansion)
    462                     count++;
    463                 count++;
    464                 isAfterExpansion = true;
    465                 continue;
    466             }
    467             isAfterExpansion = false;
    468         }
    469     } else {
    470         for (size_t i = length; i > 0; --i) {
    471             UChar32 character = characters[i - 1];
    472             if (treatAsSpace(character)) {
    473                 count++;
    474                 isAfterExpansion = true;
    475                 continue;
    476             }
    477             if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
    478                 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
    479                 i--;
    480             }
    481             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
    482                 if (!isAfterExpansion)
    483                     count++;
    484                 count++;
    485                 isAfterExpansion = true;
    486                 continue;
    487             }
    488             isAfterExpansion = false;
    489         }
    490     }
    491     return count;
    492 }
    493 
    494 bool Font::canReceiveTextEmphasis(UChar32 c)
    495 {
    496     CharCategory category = Unicode::category(c);
    497     if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
    498         return false;
    499 
    500     // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
    501     if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
    502         || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
    503         return false;
    504 
    505     return true;
    506 }
    507 
    508 }
    509