Home | History | Annotate | Download | only in graphics
      1 /**
      2  * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved.
      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 "FloatRect.h"
     27 #include "FontCache.h"
     28 #include "FontFallbackList.h"
     29 #include "GlyphBuffer.h"
     30 #include "GlyphPageTreeNode.h"
     31 #include "SimpleFontData.h"
     32 #include "TextRun.h"
     33 #include "WidthIterator.h"
     34 #include <wtf/MathExtras.h>
     35 #include <wtf/unicode/CharacterNames.h>
     36 #include <wtf/unicode/Unicode.h>
     37 
     38 using namespace WTF;
     39 using namespace Unicode;
     40 
     41 namespace WebCore {
     42 
     43 GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const
     44 {
     45     ASSERT(isMainThread());
     46 
     47     if (variant == AutoVariant) {
     48         if (m_fontDescription.smallCaps()) {
     49             UChar32 upperC = toUpper(c);
     50             if (upperC != c) {
     51                 c = upperC;
     52                 variant = SmallCapsVariant;
     53             } else
     54                 variant = NormalVariant;
     55         } else
     56             variant = NormalVariant;
     57     }
     58 
     59     if (mirror)
     60         c = mirroredChar(c);
     61 
     62     unsigned pageNumber = (c / GlyphPage::size);
     63 
     64     GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
     65     if (!node) {
     66         node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
     67         if (pageNumber)
     68             m_fontList->m_pages.set(pageNumber, node);
     69         else
     70             m_fontList->m_pageZero = node;
     71     }
     72 
     73     GlyphPage* page;
     74     if (variant == NormalVariant) {
     75         // Fastest loop, for the common case (normal variant).
     76         while (true) {
     77             page = node->page();
     78             if (page) {
     79                 GlyphData data = page->glyphDataForCharacter(c);
     80                 if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback()))
     81                     return data;
     82 
     83                 if (data.fontData) {
     84                     if (isCJKIdeographOrSymbol(c)) {
     85                         if (!data.fontData->hasVerticalGlyphs()) {
     86                             // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs
     87                             // to make sure you get a square (even for broken glyphs like symbols used for punctuation).
     88                             const SimpleFontData* brokenIdeographFontData = data.fontData->brokenIdeographFontData();
     89                             GlyphPageTreeNode* brokenIdeographNode = GlyphPageTreeNode::getRootChild(brokenIdeographFontData, pageNumber);
     90                             const GlyphPage* brokenIdeographPage = brokenIdeographNode->page();
     91                             if (brokenIdeographPage) {
     92                                 GlyphData brokenIdeographData = brokenIdeographPage->glyphDataForCharacter(c);
     93                                 if (brokenIdeographData.fontData)
     94                                     return brokenIdeographData;
     95                             }
     96 
     97                             // Shouldn't be possible to even reach this point.
     98                             ASSERT_NOT_REACHED();
     99                         }
    100                     } else {
    101                         if (m_fontDescription.textOrientation() == TextOrientationVerticalRight) {
    102                             const SimpleFontData* verticalRightFontData = data.fontData->verticalRightOrientationFontData();
    103                             GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData, pageNumber);
    104                             const GlyphPage* verticalRightPage = verticalRightNode->page();
    105                             if (verticalRightPage) {
    106                                 GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(c);
    107                                 // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked
    108                                 // into it.
    109                                 if (data.glyph != verticalRightData.glyph)
    110                                     return data;
    111                                 // The glyphs are identical, meaning that we should just use the horizontal glyph.
    112                                 if (verticalRightData.fontData)
    113                                     return verticalRightData;
    114                             }
    115                         } else if (m_fontDescription.textOrientation() == TextOrientationUpright) {
    116                             const SimpleFontData* uprightFontData = data.fontData->uprightOrientationFontData();
    117                             GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData, pageNumber);
    118                             const GlyphPage* uprightPage = uprightNode->page();
    119                             if (uprightPage) {
    120                                 GlyphData uprightData = uprightPage->glyphDataForCharacter(c);
    121                                 // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright.
    122                                 if (data.glyph == uprightData.glyph)
    123                                     return data;
    124                                 // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that
    125                                 // glyph, so we fall back to the upright data and use the horizontal glyph.
    126                                 if (uprightData.fontData)
    127                                     return uprightData;
    128                             }
    129                         }
    130 
    131                         // Shouldn't be possible to even reach this point.
    132                         ASSERT_NOT_REACHED();
    133                     }
    134                     return data;
    135                 }
    136 
    137                 if (node->isSystemFallback())
    138                     break;
    139             }
    140 
    141             // Proceed with the fallback list.
    142             node = node->getChild(fontDataAt(node->level()), pageNumber);
    143             if (pageNumber)
    144                 m_fontList->m_pages.set(pageNumber, node);
    145             else
    146                 m_fontList->m_pageZero = node;
    147         }
    148     } else {
    149         while (true) {
    150             page = node->page();
    151             if (page) {
    152                 GlyphData data = page->glyphDataForCharacter(c);
    153                 if (data.fontData) {
    154                     // The variantFontData function should not normally return 0.
    155                     // But if it does, we will just render the capital letter big.
    156                     const SimpleFontData* variantFontData = data.fontData->variantFontData(m_fontDescription, variant);
    157                     if (!variantFontData)
    158                         return data;
    159 
    160                     GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData, pageNumber);
    161                     const GlyphPage* variantPage = variantNode->page();
    162                     if (variantPage) {
    163                         GlyphData data = variantPage->glyphDataForCharacter(c);
    164                         if (data.fontData)
    165                             return data;
    166                     }
    167 
    168                     // Do not attempt system fallback off the variantFontData. This is the very unlikely case that
    169                     // a font has the lowercase character but the small caps font does not have its uppercase version.
    170                     return variantFontData->missingGlyphData();
    171                 }
    172 
    173                 if (node->isSystemFallback())
    174                     break;
    175             }
    176 
    177             // Proceed with the fallback list.
    178             node = node->getChild(fontDataAt(node->level()), pageNumber);
    179             if (pageNumber)
    180                 m_fontList->m_pages.set(pageNumber, node);
    181             else
    182                 m_fontList->m_pageZero = node;
    183         }
    184     }
    185 
    186     ASSERT(page);
    187     ASSERT(node->isSystemFallback());
    188 
    189     // System fallback is character-dependent. When we get here, we
    190     // know that the character in question isn't in the system fallback
    191     // font's glyph page. Try to lazily create it here.
    192     UChar codeUnits[2];
    193     int codeUnitsLength;
    194     if (c <= 0xFFFF) {
    195         codeUnits[0] = Font::normalizeSpaces(c);
    196         codeUnitsLength = 1;
    197     } else {
    198         codeUnits[0] = U16_LEAD(c);
    199         codeUnits[1] = U16_TRAIL(c);
    200         codeUnitsLength = 2;
    201     }
    202     const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
    203     if (variant != NormalVariant && characterFontData)
    204         characterFontData = characterFontData->variantFontData(m_fontDescription, variant);
    205     if (characterFontData) {
    206         // Got the fallback glyph and font.
    207         GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
    208         GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
    209         // Cache it so we don't have to do system fallback again next time.
    210         if (variant == NormalVariant) {
    211 #if OS(WINCE)
    212             // missingGlyphData returns a null character, which is not suitable for GDI to display.
    213             // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
    214             // display the character, probably because the font package is not installed correctly.
    215             // So we just always set the glyph to be same as the character, and let GDI solve it.
    216             page->setGlyphDataForCharacter(c, c, characterFontData);
    217             return page->glyphDataForCharacter(c);
    218 #else
    219             page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
    220 #endif
    221         }
    222         return data;
    223     }
    224 
    225     // Even system fallback can fail; use the missing glyph in that case.
    226     // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
    227     GlyphData data = primaryFont()->missingGlyphData();
    228     if (variant == NormalVariant) {
    229 #if OS(WINCE)
    230         // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
    231         page->setGlyphDataForCharacter(c, c, data.fontData);
    232         return page->glyphDataForCharacter(c);
    233 #else
    234         page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
    235 #endif
    236     }
    237     return data;
    238 }
    239 
    240 bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const
    241 {
    242     unsigned pageNumber = (character / GlyphPage::size);
    243 
    244     GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber);
    245     GlyphPage* page = node->page();
    246 
    247     return page && page->fontDataForCharacter(character);
    248 }
    249 
    250 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
    251 // standard emphasis marks do so.
    252 bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const
    253 {
    254     if (mark.isEmpty())
    255         return false;
    256 
    257 #if ENABLE(SVG_FONTS)
    258     // FIXME: Implement for SVG fonts.
    259     if (primaryFont()->isSVGFont())
    260         return false;
    261 #endif
    262 
    263     UChar32 character = mark[0];
    264 
    265     if (U16_IS_SURROGATE(character)) {
    266         if (!U16_IS_SURROGATE_LEAD(character))
    267             return false;
    268 
    269         if (mark.length() < 2)
    270             return false;
    271 
    272         UChar low = mark[1];
    273         if (!U16_IS_TRAIL(low))
    274             return false;
    275 
    276         character = U16_GET_SUPPLEMENTARY(character, low);
    277     }
    278 
    279     glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant);
    280     return true;
    281 }
    282 
    283 int Font::emphasisMarkAscent(const AtomicString& mark) const
    284 {
    285     GlyphData markGlyphData;
    286     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
    287         return 0;
    288 
    289     const SimpleFontData* markFontData = markGlyphData.fontData;
    290     ASSERT(markFontData);
    291     if (!markFontData)
    292         return 0;
    293 
    294     return markFontData->fontMetrics().ascent();
    295 }
    296 
    297 int Font::emphasisMarkDescent(const AtomicString& mark) const
    298 {
    299     GlyphData markGlyphData;
    300     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
    301         return 0;
    302 
    303     const SimpleFontData* markFontData = markGlyphData.fontData;
    304     ASSERT(markFontData);
    305     if (!markFontData)
    306         return 0;
    307 
    308     return markFontData->fontMetrics().descent();
    309 }
    310 
    311 int Font::emphasisMarkHeight(const AtomicString& mark) const
    312 {
    313     GlyphData markGlyphData;
    314     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
    315         return 0;
    316 
    317     const SimpleFontData* markFontData = markGlyphData.fontData;
    318     ASSERT(markFontData);
    319     if (!markFontData)
    320         return 0;
    321 
    322     return markFontData->fontMetrics().height();
    323 }
    324 
    325 float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
    326 {
    327     float initialAdvance;
    328 
    329     WidthIterator it(this, run, 0, false, forTextEmphasis);
    330     it.advance(from);
    331     float beforeWidth = it.m_runWidthSoFar;
    332     it.advance(to, &glyphBuffer);
    333 
    334     if (glyphBuffer.isEmpty())
    335         return 0;
    336 
    337     float afterWidth = it.m_runWidthSoFar;
    338 
    339     if (run.rtl()) {
    340         it.advance(run.length());
    341         initialAdvance = it.m_runWidthSoFar - afterWidth;
    342     } else
    343         initialAdvance = beforeWidth;
    344 
    345     if (run.rtl()) {
    346         for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
    347             glyphBuffer.swap(i, end);
    348     }
    349 
    350     return initialAdvance;
    351 }
    352 
    353 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
    354 {
    355     // This glyph buffer holds our glyphs+advances+font data for each glyph.
    356     GlyphBuffer glyphBuffer;
    357 
    358     float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
    359 
    360     if (glyphBuffer.isEmpty())
    361         return;
    362 
    363     FloatPoint startPoint(startX, point.y());
    364     drawGlyphBuffer(context, glyphBuffer, startPoint);
    365 }
    366 
    367 void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
    368 {
    369     GlyphBuffer glyphBuffer;
    370     float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
    371 
    372     if (glyphBuffer.isEmpty())
    373         return;
    374 
    375     drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
    376 }
    377 
    378 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const
    379 {
    380     // Draw each contiguous run of glyphs that use the same font data.
    381     const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
    382     FloatSize offset = glyphBuffer.offsetAt(0);
    383     FloatPoint startPoint(point);
    384     float nextX = startPoint.x();
    385     int lastFrom = 0;
    386     int nextGlyph = 0;
    387     while (nextGlyph < glyphBuffer.size()) {
    388         const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
    389         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
    390         if (nextFontData != fontData || nextOffset != offset) {
    391             drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
    392 
    393             lastFrom = nextGlyph;
    394             fontData = nextFontData;
    395             offset = nextOffset;
    396             startPoint.setX(nextX);
    397         }
    398         nextX += glyphBuffer.advanceAt(nextGlyph);
    399         nextGlyph++;
    400     }
    401 
    402     drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
    403 }
    404 
    405 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph)
    406 {
    407     if (fontData->platformData().orientation() == Horizontal) {
    408         FloatRect bounds = fontData->boundsForGlyph(glyph);
    409         return bounds.x() + bounds.width() / 2;
    410     }
    411     // FIXME: Use glyph bounds once they make sense for vertical fonts.
    412     return fontData->widthForGlyph(glyph) / 2;
    413 }
    414 
    415 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
    416 {
    417     return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i));
    418 }
    419 
    420 void Font::drawEmphasisMarks(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
    421 {
    422     GlyphData markGlyphData;
    423     if (!getEmphasisMarkGlyphData(mark, markGlyphData))
    424         return;
    425 
    426     const SimpleFontData* markFontData = markGlyphData.fontData;
    427     ASSERT(markFontData);
    428     if (!markFontData)
    429         return;
    430 
    431     Glyph markGlyph = markGlyphData.glyph;
    432     Glyph spaceGlyph = markFontData->spaceGlyph();
    433 
    434     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
    435     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
    436 
    437     GlyphBuffer markBuffer;
    438     for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
    439         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
    440         float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph;
    441         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
    442         middleOfLastGlyph = middleOfNextGlyph;
    443     }
    444     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
    445 
    446     drawGlyphBuffer(context, markBuffer, startPoint);
    447 }
    448 
    449 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
    450 {
    451     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
    452     it.advance(run.length(), glyphBuffer);
    453 
    454     if (glyphOverflow) {
    455         glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
    456         glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
    457         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
    458         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
    459     }
    460 
    461     return it.m_runWidthSoFar;
    462 }
    463 
    464 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
    465 {
    466     WidthIterator it(this, run);
    467     it.advance(from);
    468     float beforeWidth = it.m_runWidthSoFar;
    469     it.advance(to);
    470     float afterWidth = it.m_runWidthSoFar;
    471 
    472     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning.
    473     if (run.rtl()) {
    474         it.advance(run.length());
    475         float totalWidth = it.m_runWidthSoFar;
    476         return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
    477     }
    478 
    479     return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
    480 }
    481 
    482 int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
    483 {
    484     float delta = x;
    485 
    486     WidthIterator it(this, run);
    487     GlyphBuffer localGlyphBuffer;
    488     unsigned offset;
    489     if (run.rtl()) {
    490         delta -= floatWidthForSimpleText(run, 0);
    491         while (1) {
    492             offset = it.m_currentCharacter;
    493             float w;
    494             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
    495                 break;
    496             delta += w;
    497             if (includePartialGlyphs) {
    498                 if (delta - w / 2 >= 0)
    499                     break;
    500             } else {
    501                 if (delta >= 0)
    502                     break;
    503             }
    504         }
    505     } else {
    506         while (1) {
    507             offset = it.m_currentCharacter;
    508             float w;
    509             if (!it.advanceOneCharacter(w, &localGlyphBuffer))
    510                 break;
    511             delta -= w;
    512             if (includePartialGlyphs) {
    513                 if (delta + w / 2 <= 0)
    514                     break;
    515             } else {
    516                 if (delta <= 0)
    517                     break;
    518             }
    519         }
    520     }
    521 
    522     return offset;
    523 }
    524 
    525 }
    526