Home | History | Annotate | Download | only in graphics
      1 /**
      2  * Copyright (C) 2003, 2006 Apple Computer, Inc.
      3  * Copyright (C) 2008 Holger Hans Peter Freyther
      4  * Copyright (C) 2009 Torch Mobile, Inc.
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Library General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Library General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Library General Public License
     17  * along with this library; see the file COPYING.LIB.  If not, write to
     18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19  * Boston, MA 02110-1301, USA.
     20  *
     21  */
     22 
     23 #include "config.h"
     24 #include "Font.h"
     25 
     26 #include "CharacterNames.h"
     27 #include "FontCache.h"
     28 #include "FontFallbackList.h"
     29 #include "FloatRect.h"
     30 #include "GlyphBuffer.h"
     31 #include "GlyphPageTreeNode.h"
     32 #include "IntPoint.h"
     33 #include "SimpleFontData.h"
     34 #include "WidthIterator.h"
     35 
     36 #include <wtf/unicode/Unicode.h>
     37 #include <wtf/MathExtras.h>
     38 
     39 using namespace WTF;
     40 using namespace Unicode;
     41 
     42 namespace WebCore {
     43 
     44 GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const
     45 {
     46     ASSERT(isMainThread());
     47 
     48     bool useSmallCapsFont = forceSmallCaps;
     49     if (m_fontDescription.smallCaps()) {
     50         UChar32 upperC = toUpper(c);
     51         if (upperC != c) {
     52             c = upperC;
     53             useSmallCapsFont = true;
     54         }
     55     }
     56 
     57     if (mirror)
     58         c = mirroredChar(c);
     59 
     60     unsigned pageNumber = (c / GlyphPage::size);
     61 
     62     GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
     63     if (!node) {
     64         node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
     65         if (pageNumber)
     66             m_fontList->m_pages.set(pageNumber, node);
     67         else
     68             m_fontList->m_pageZero = node;
     69     }
     70 
     71     GlyphPage* page;
     72     if (!useSmallCapsFont) {
     73         // Fastest loop, for the common case (not small caps).
     74         while (true) {
     75             page = node->page();
     76             if (page) {
     77                 GlyphData data = page->glyphDataForCharacter(c);
     78                 if (data.fontData)
     79                     return data;
     80                 if (node->isSystemFallback())
     81                     break;
     82             }
     83 
     84             // Proceed with the fallback list.
     85             node = node->getChild(fontDataAt(node->level()), pageNumber);
     86             if (pageNumber)
     87                 m_fontList->m_pages.set(pageNumber, node);
     88             else
     89                 m_fontList->m_pageZero = node;
     90         }
     91     } else {
     92         while (true) {
     93             page = node->page();
     94             if (page) {
     95                 GlyphData data = page->glyphDataForCharacter(c);
     96                 if (data.fontData) {
     97                     // The smallCapsFontData function should not normally return 0.
     98                     // But if it does, we will just render the capital letter big.
     99                     const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription);
    100                     if (!smallCapsFontData)
    101                         return data;
    102 
    103                     GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber);
    104                     const GlyphPage* smallCapsPage = smallCapsNode->page();
    105                     if (smallCapsPage) {
    106                         GlyphData data = smallCapsPage->glyphDataForCharacter(c);
    107                         if (data.fontData)
    108                             return data;
    109                     }
    110 
    111                     // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that
    112                     // a font has the lowercase character but the small caps font does not have its uppercase version.
    113                     return smallCapsFontData->missingGlyphData();
    114                 }
    115 
    116                 if (node->isSystemFallback())
    117                     break;
    118             }
    119 
    120             // Proceed with the fallback list.
    121             node = node->getChild(fontDataAt(node->level()), pageNumber);
    122             if (pageNumber)
    123                 m_fontList->m_pages.set(pageNumber, node);
    124             else
    125                 m_fontList->m_pageZero = node;
    126         }
    127     }
    128 
    129     ASSERT(page);
    130     ASSERT(node->isSystemFallback());
    131 
    132     // System fallback is character-dependent. When we get here, we
    133     // know that the character in question isn't in the system fallback
    134     // font's glyph page. Try to lazily create it here.
    135     UChar codeUnits[2];
    136     int codeUnitsLength;
    137     if (c <= 0xFFFF) {
    138         codeUnits[0] = Font::normalizeSpaces(c);
    139         codeUnitsLength = 1;
    140     } else {
    141         codeUnits[0] = U16_LEAD(c);
    142         codeUnits[1] = U16_TRAIL(c);
    143         codeUnitsLength = 2;
    144     }
    145     const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
    146     if (useSmallCapsFont && characterFontData)
    147         characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
    148     if (characterFontData) {
    149         // Got the fallback glyph and font.
    150         GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
    151         GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
    152         // Cache it so we don't have to do system fallback again next time.
    153         if (!useSmallCapsFont) {
    154 #if OS(WINCE)
    155             // missingGlyphData returns a null character, which is not suitable for GDI to display.
    156             // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
    157             // display the character, probably because the font package is not installed correctly.
    158             // So we just always set the glyph to be same as the character, and let GDI solve it.
    159             page->setGlyphDataForCharacter(c, c, characterFontData);
    160             return page->glyphDataForCharacter(c);
    161 #else
    162             page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
    163 #endif
    164         }
    165         return data;
    166     }
    167 
    168     // Even system fallback can fail; use the missing glyph in that case.
    169     // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
    170     GlyphData data = primaryFont()->missingGlyphData();
    171     if (!useSmallCapsFont) {
    172 #if OS(WINCE)
    173         // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
    174         page->setGlyphDataForCharacter(c, c, data.fontData);
    175         return page->glyphDataForCharacter(c);
    176 #else
    177         page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
    178 #endif
    179     }
    180     return data;
    181 }
    182 
    183 void Font::setCodePath(CodePath p)
    184 {
    185     s_codePath = p;
    186 }
    187 
    188 Font::CodePath Font::codePath()
    189 {
    190     return s_codePath;
    191 }
    192 
    193 bool Font::canUseGlyphCache(const TextRun& run) const
    194 {
    195     switch (s_codePath) {
    196         case Auto:
    197             break;
    198         case Simple:
    199             return true;
    200         case Complex:
    201             return false;
    202     }
    203 
    204     // Start from 0 since drawing and highlighting also measure the characters before run->from
    205     for (int i = 0; i < run.length(); i++) {
    206         const UChar c = run[i];
    207         if (c < 0x300)      // U+0300 through U+036F Combining diacritical marks
    208             continue;
    209         if (c <= 0x36F)
    210             return false;
    211 
    212         if (c < 0x0591 || c == 0x05BE)     // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
    213             continue;
    214         if (c <= 0x05CF)
    215             return false;
    216 
    217         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
    218             continue;
    219         if (c <= 0x1059)
    220             return false;
    221 
    222         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)
    223             continue;
    224         if (c <= 0x11FF)
    225             return false;
    226 
    227         if (c < 0x1780)     // U+1780 through U+18AF Khmer, Mongolian
    228             continue;
    229         if (c <= 0x18AF)
    230             return false;
    231 
    232         if (c < 0x1900)     // U+1900 through U+194F Limbu (Unicode 4.0)
    233             continue;
    234         if (c <= 0x194F)
    235             return false;
    236 
    237         if (c < 0x20D0)     // U+20D0 through U+20FF Combining marks for symbols
    238             continue;
    239         if (c <= 0x20FF)
    240             return false;
    241 
    242         if (c < 0xFE20)     // U+FE20 through U+FE2F Combining half marks
    243             continue;
    244         if (c <= 0xFE2F)
    245             return false;
    246     }
    247 
    248     if (typesettingFeatures())
    249         return false;
    250 
    251     return true;
    252 
    253 }
    254 
    255 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
    256 {
    257     // This glyph buffer holds our glyphs+advances+font data for each glyph.
    258     GlyphBuffer glyphBuffer;
    259 
    260     float startX = point.x();
    261     WidthIterator it(this, run);
    262     it.advance(from);
    263     float beforeWidth = it.m_runWidthSoFar;
    264     it.advance(to, &glyphBuffer);
    265 
    266     // We couldn't generate any glyphs for the run.  Give up.
    267     if (glyphBuffer.isEmpty())
    268         return;
    269 
    270     float afterWidth = it.m_runWidthSoFar;
    271 
    272     if (run.rtl()) {
    273         float finalRoundingWidth = it.m_finalRoundingWidth;
    274         it.advance(run.length());
    275         startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
    276     } else
    277         startX += beforeWidth;
    278 
    279     // Swap the order of the glyphs if right-to-left.
    280     if (run.rtl())
    281         for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
    282             glyphBuffer.swap(i, end);
    283 
    284     // Calculate the starting point of the glyphs to be displayed by adding
    285     // all the advances up to the first glyph.
    286     FloatPoint startPoint(startX, point.y());
    287     drawGlyphBuffer(context, glyphBuffer, run, startPoint);
    288 }
    289 
    290 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const TextRun&, const FloatPoint& point) const
    291 {
    292     // Draw each contiguous run of glyphs that use the same font data.
    293     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
    294     FloatSize offset = glyphBuffer.offsetAt(0);
    295     FloatPoint startPoint(point);
    296     float nextX = startPoint.x();
    297     int lastFrom = 0;
    298     int nextGlyph = 0;
    299     while (nextGlyph < glyphBuffer.size()) {
    300         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
    301         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
    302         if (nextFontData != fontData || nextOffset != offset) {
    303             drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
    304 
    305             lastFrom = nextGlyph;
    306             fontData = nextFontData;
    307             offset = nextOffset;
    308             startPoint.setX(nextX);
    309         }
    310         nextX += glyphBuffer.advanceAt(nextGlyph);
    311         nextGlyph++;
    312     }
    313 
    314     drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
    315 }
    316 
    317 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts) const
    318 {
    319     WidthIterator it(this, run, fallbackFonts);
    320     it.advance(run.length(), glyphBuffer);
    321     return it.m_runWidthSoFar;
    322 }
    323 
    324 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
    325 {
    326     WidthIterator it(this, run);
    327     it.advance(from);
    328     float beforeWidth = it.m_runWidthSoFar;
    329     it.advance(to);
    330     float afterWidth = it.m_runWidthSoFar;
    331 
    332     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
    333     if (run.rtl()) {
    334         it.advance(run.length());
    335         float totalWidth = it.m_runWidthSoFar;
    336         return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
    337     } else {
    338         return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
    339     }
    340 }
    341 
    342 int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
    343 {
    344     float delta = (float)x;
    345 
    346     WidthIterator it(this, run);
    347     GlyphBuffer localGlyphBuffer;
    348     unsigned offset;
    349     if (run.rtl()) {
    350         delta -= floatWidthForSimpleText(run, 0);
    351         while (1) {
    352             offset = it.m_currentCharacter;
    353             float w;
    354             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
    355                 break;
    356             delta += w;
    357             if (includePartialGlyphs) {
    358                 if (delta - w / 2 >= 0)
    359                     break;
    360             } else {
    361                 if (delta >= 0)
    362                     break;
    363             }
    364         }
    365     } else {
    366         while (1) {
    367             offset = it.m_currentCharacter;
    368             float w;
    369             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
    370                 break;
    371             delta -= w;
    372             if (includePartialGlyphs) {
    373                 if (delta + w / 2 <= 0)
    374                     break;
    375             } else {
    376                 if (delta <= 0)
    377                     break;
    378             }
    379         }
    380     }
    381 
    382     return offset;
    383 }
    384 
    385 }
    386