Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 #include "platform/fonts/Font.h"
     27 
     28 #include "platform/fonts/Character.h"
     29 #include "platform/fonts/FontFallbackList.h"
     30 #include "platform/fonts/GlyphBuffer.h"
     31 #include "platform/fonts/SimpleFontData.h"
     32 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h"
     33 #include "platform/fonts/mac/ComplexTextController.h"
     34 #include "platform/geometry/IntRect.h"
     35 #include "platform/graphics/GraphicsContext.h"
     36 #include "platform/text/TextRun.h"
     37 #include "wtf/MathExtras.h"
     38 
     39 namespace blink {
     40 
     41 static bool preferHarfBuzz(const Font* font)
     42 {
     43     const FontDescription& description = font->fontDescription();
     44     return description.featureSettings() && description.featureSettings()->size() > 0;
     45 }
     46 
     47 FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h,
     48                                             int from, int to) const
     49 {
     50     if (preferHarfBuzz(this)) {
     51         HarfBuzzShaper shaper(this, run);
     52         if (shaper.shape())
     53             return shaper.selectionRect(point, h, from, to);
     54     }
     55     ComplexTextController controller(this, run);
     56     controller.advance(from);
     57     float beforeWidth = controller.runWidthSoFar();
     58     controller.advance(to);
     59     float afterWidth = controller.runWidthSoFar();
     60 
     61     // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
     62     if (run.rtl()) {
     63         float totalWidth = controller.totalWidth();
     64         return FloatRect(floorf(point.x() + totalWidth - afterWidth), point.y(), roundf(point.x() + totalWidth - beforeWidth) - floorf(point.x() + totalWidth - afterWidth), h);
     65     }
     66 
     67     return FloatRect(floorf(point.x() + beforeWidth), point.y(), roundf(point.x() + afterWidth) - floorf(point.x() + beforeWidth), h);
     68 }
     69 
     70 float Font::getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
     71 {
     72     float initialAdvance;
     73 
     74     ComplexTextController controller(this, runInfo.run, false, 0, forTextEmphasis);
     75     controller.advance(runInfo.from);
     76     float beforeWidth = controller.runWidthSoFar();
     77     controller.advance(runInfo.to, &glyphBuffer);
     78 
     79     if (glyphBuffer.isEmpty())
     80         return 0;
     81 
     82     float afterWidth = controller.runWidthSoFar();
     83 
     84     if (runInfo.run.rtl()) {
     85         initialAdvance = controller.totalWidth() - afterWidth;
     86         glyphBuffer.reverse();
     87     } else
     88         initialAdvance = beforeWidth;
     89 
     90     return initialAdvance;
     91 }
     92 
     93 float Font::drawComplexText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point) const
     94 {
     95     if (preferHarfBuzz(this)) {
     96         GlyphBuffer glyphBuffer;
     97         HarfBuzzShaper shaper(this, runInfo.run);
     98         shaper.setDrawRange(runInfo.from, runInfo.to);
     99         if (shaper.shape(&glyphBuffer)) {
    100             return drawGlyphBuffer(context, runInfo, glyphBuffer, point);
    101         }
    102     }
    103     // This glyph buffer holds our glyphs + advances + font data for each glyph.
    104     GlyphBuffer glyphBuffer;
    105 
    106     float startX = point.x() + getGlyphsAndAdvancesForComplexText(runInfo, glyphBuffer);
    107 
    108     // We couldn't generate any glyphs for the run.  Give up.
    109     if (glyphBuffer.isEmpty())
    110         return 0;
    111 
    112     // Draw the glyph buffer now at the starting point returned in startX.
    113     FloatPoint startPoint(startX, point.y());
    114     return drawGlyphBuffer(context, runInfo, glyphBuffer, startPoint);
    115 }
    116 
    117 void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
    118 {
    119     GlyphBuffer glyphBuffer;
    120     float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo, glyphBuffer, ForTextEmphasis);
    121 
    122     if (glyphBuffer.isEmpty())
    123         return;
    124 
    125     drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
    126 }
    127 
    128 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, IntRectExtent* glyphBounds) const
    129 {
    130     if (preferHarfBuzz(this)) {
    131         HarfBuzzShaper shaper(this, run);
    132         if (shaper.shape())
    133             return shaper.totalWidth();
    134     }
    135     ComplexTextController controller(this, run, true, fallbackFonts);
    136     glyphBounds->setTop(floorf(-controller.minGlyphBoundingBoxY()));
    137     glyphBounds->setBottom(ceilf(controller.maxGlyphBoundingBoxY()));
    138     glyphBounds->setLeft(std::max<int>(0, floorf(-controller.minGlyphBoundingBoxX())));
    139     glyphBounds->setRight(std::max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth())));
    140 
    141     return controller.totalWidth();
    142 }
    143 
    144 int Font::offsetForPositionForComplexText(const TextRun& run, float x, bool includePartialGlyphs) const
    145 {
    146     if (preferHarfBuzz(this)) {
    147         HarfBuzzShaper shaper(this, run);
    148         if (shaper.shape())
    149             return shaper.offsetForPosition(x);
    150     }
    151     ComplexTextController controller(this, run);
    152     return controller.offsetForPosition(x, includePartialGlyphs);
    153 }
    154 
    155 const SimpleFontData* Font::fontDataForCombiningCharacterSequence(const UChar* characters, size_t length, FontDataVariant variant) const
    156 {
    157     UChar32 baseCharacter;
    158     size_t baseCharacterLength = 0;
    159     U16_NEXT(characters, baseCharacterLength, length, baseCharacter);
    160 
    161     GlyphData baseCharacterGlyphData = glyphDataForCharacter(baseCharacter, false, false, variant);
    162 
    163     if (!baseCharacterGlyphData.glyph)
    164         return 0;
    165 
    166     if (length == baseCharacterLength)
    167         return baseCharacterGlyphData.fontData;
    168 
    169     bool triedBaseCharacterFontData = false;
    170 
    171     unsigned i = 0;
    172     for (const FontData* fontData = fontDataAt(0); fontData; fontData = fontDataAt(++i)) {
    173         const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(baseCharacter);
    174         if (variant == NormalVariant) {
    175             if (simpleFontData->platformData().orientation() == Vertical) {
    176                 if (Character::isCJKIdeographOrSymbol(baseCharacter) && !simpleFontData->hasVerticalGlyphs()) {
    177                     variant = BrokenIdeographVariant;
    178                     simpleFontData = simpleFontData->brokenIdeographFontData().get();
    179                 } else if (m_fontDescription.nonCJKGlyphOrientation() == NonCJKGlyphOrientationVerticalRight) {
    180                     SimpleFontData* verticalRightFontData = simpleFontData->verticalRightOrientationFontData().get();
    181                     Glyph verticalRightGlyph = verticalRightFontData->glyphForCharacter(baseCharacter);
    182                     if (verticalRightGlyph == baseCharacterGlyphData.glyph)
    183                         simpleFontData = verticalRightFontData;
    184                 } else {
    185                     SimpleFontData* uprightFontData = simpleFontData->uprightOrientationFontData().get();
    186                     Glyph uprightGlyph = uprightFontData->glyphForCharacter(baseCharacter);
    187                     if (uprightGlyph != baseCharacterGlyphData.glyph)
    188                         simpleFontData = uprightFontData;
    189                 }
    190             }
    191         } else {
    192             if (const SimpleFontData* variantFontData = simpleFontData->variantFontData(m_fontDescription, variant).get())
    193                 simpleFontData = variantFontData;
    194         }
    195 
    196         if (simpleFontData == baseCharacterGlyphData.fontData)
    197             triedBaseCharacterFontData = true;
    198 
    199         if (simpleFontData->canRenderCombiningCharacterSequence(characters, length))
    200             return simpleFontData;
    201     }
    202 
    203     if (!triedBaseCharacterFontData && baseCharacterGlyphData.fontData && baseCharacterGlyphData.fontData->canRenderCombiningCharacterSequence(characters, length))
    204         return baseCharacterGlyphData.fontData;
    205 
    206     return SimpleFontData::systemFallback();
    207 }
    208 
    209 } // namespace blink
    210