Home | History | Annotate | Download | only in harfbuzz
      1 /*
      2  * Copyright (c) 2007, 2008, 2010 Google 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/platform/graphics/Font.h"
     33 
     34 #include "core/platform/NotImplemented.h"
     35 #include "core/platform/graphics/FloatRect.h"
     36 #include "core/platform/graphics/GlyphBuffer.h"
     37 #include "core/platform/graphics/GraphicsContext.h"
     38 #include "core/platform/graphics/SimpleFontData.h"
     39 #include "core/platform/graphics/harfbuzz/HarfBuzzShaper.h"
     40 
     41 #include "SkPaint.h"
     42 #include "SkTemplates.h"
     43 
     44 #include "wtf/unicode/Unicode.h"
     45 
     46 namespace WebCore {
     47 
     48 bool Font::canReturnFallbackFontsForComplexText()
     49 {
     50     return false;
     51 }
     52 
     53 bool Font::canExpandAroundIdeographsInComplexText()
     54 {
     55     return false;
     56 }
     57 
     58 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
     59                       const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
     60                       const FloatPoint& point, const FloatRect& textRect) const {
     61     SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
     62 
     63     const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
     64     SkScalar x = SkFloatToScalar(point.x());
     65     SkScalar y = SkFloatToScalar(point.y());
     66 
     67     // FIXME: text rendering speed:
     68     // Android has code in their WebCore fork to special case when the
     69     // GlyphBuffer has no advances other than the defaults. In that case the
     70     // text drawing can proceed faster. However, it's unclear when those
     71     // patches may be upstreamed to WebKit so we always use the slower path
     72     // here.
     73     const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
     74     SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs);
     75     SkPoint* pos = storage.get();
     76     SkPoint* vPosBegin = storage2.get();
     77     SkPoint* vPosEnd = storage3.get();
     78 
     79     bool isVertical = font->platformData().orientation() == Vertical;
     80     SkScalar verticalPosCompensation = isVertical ? SkFloatToScalar((font->fontMetrics().floatHeight() - font->fontMetrics().floatAscent()) / 2) : 0;
     81     for (int i = 0; i < numGlyphs; i++) {
     82         SkScalar myWidth = SkFloatToScalar(adv[i].width());
     83         pos[i].set(x, y);
     84         if (isVertical) {
     85             // In vertical mode, we need to align the left of ideographics to the vertical baseline.
     86             // (Note vertical/horizontal are in absolute orientation, that is, here x is vertical.)
     87             // However, when the glyph is drawn in drawTextOnPath(), the baseline is the horizontal path,
     88             // so the ideographics will look shifted to the bottom-right direction because the ascent is
     89             // applied vertically. Compensate the position so that ascent will look like to be applied
     90             // horizontally.
     91             SkScalar bottom = x + myWidth - verticalPosCompensation;
     92             SkScalar left = y + verticalPosCompensation;
     93             vPosBegin[i].set(bottom, left);
     94             vPosEnd[i].set(bottom, left - myWidth);
     95         }
     96         x += myWidth;
     97         y += SkFloatToScalar(adv[i].height());
     98     }
     99 
    100     TextDrawingModeFlags textMode = gc->textDrawingMode();
    101 
    102     // We draw text up to two times (once for fill, once for stroke).
    103     if (textMode & TextModeFill) {
    104         SkPaint paint;
    105         gc->setupPaintForFilling(&paint);
    106         font->platformData().setupPaint(&paint);
    107         gc->adjustTextRenderMode(&paint);
    108         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    109 
    110         if (isVertical) {
    111             SkPath path;
    112             for (int i = 0; i < numGlyphs; ++i) {
    113                 path.reset();
    114                 path.moveTo(vPosBegin[i]);
    115                 path.lineTo(vPosEnd[i]);
    116                 gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint);
    117             }
    118         } else
    119             gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint);
    120     }
    121 
    122     if ((textMode & TextModeStroke)
    123         && gc->strokeStyle() != NoStroke
    124         && gc->strokeThickness() > 0) {
    125 
    126         SkPaint paint;
    127         gc->setupPaintForStroking(&paint);
    128         font->platformData().setupPaint(&paint);
    129         gc->adjustTextRenderMode(&paint);
    130         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    131 
    132         if (textMode & TextModeFill) {
    133             // If we also filled, we don't want to draw shadows twice.
    134             // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
    135             // Since we use the looper for shadows, we remove it (if any) now.
    136             paint.setLooper(0);
    137         }
    138 
    139         if (isVertical) {
    140             SkPath path;
    141             for (int i = 0; i < numGlyphs; ++i) {
    142                 path.reset();
    143                 path.moveTo(vPosBegin[i]);
    144                 path.lineTo(vPosEnd[i]);
    145                 gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint);
    146             }
    147         } else
    148             gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint);
    149     }
    150 }
    151 
    152 static void setupForTextPainting(SkPaint* paint, SkColor color)
    153 {
    154     paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    155     paint->setColor(color);
    156 }
    157 
    158 void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, const FloatPoint& point) const
    159 {
    160     if (!runInfo.run.length())
    161         return;
    162 
    163     TextDrawingModeFlags textMode = gc->textDrawingMode();
    164     bool fill = textMode & TextModeFill;
    165     bool stroke = (textMode & TextModeStroke)
    166         && gc->strokeStyle() != NoStroke
    167         && gc->strokeThickness() > 0;
    168 
    169     if (!fill && !stroke)
    170         return;
    171 
    172     SkPaint strokePaint, fillPaint;
    173     if (fill) {
    174         gc->setupPaintForFilling(&fillPaint);
    175         setupForTextPainting(&fillPaint, gc->fillColor().rgb());
    176     }
    177     if (stroke) {
    178         gc->setupPaintForStroking(&strokePaint);
    179         setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
    180     }
    181 
    182     GlyphBuffer glyphBuffer;
    183     HarfBuzzShaper shaper(this, runInfo.run);
    184     shaper.setDrawRange(runInfo.from, runInfo.to);
    185     if (!shaper.shape(&glyphBuffer))
    186         return;
    187     FloatPoint adjustedPoint = shaper.adjustStartPoint(point);
    188     drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint);
    189 }
    190 
    191 void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRunPaintInfo& /* runInfo */, const AtomicString& /* mark */, const FloatPoint& /* point */) const
    192 {
    193     notImplemented();
    194 }
    195 
    196 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
    197 {
    198     HarfBuzzShaper shaper(this, run);
    199     if (!shaper.shape())
    200         return 0;
    201     return shaper.totalWidth();
    202 }
    203 
    204 // Return the code point index for the given |x| offset into the text run.
    205 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
    206                                           bool includePartialGlyphs) const
    207 {
    208     HarfBuzzShaper shaper(this, run);
    209     if (!shaper.shape())
    210         return 0;
    211     return shaper.offsetForPosition(xFloat);
    212 }
    213 
    214 // Return the rectangle for selecting the given range of code-points in the TextRun.
    215 FloatRect Font::selectionRectForComplexText(const TextRun& run,
    216                                             const FloatPoint& point, int height,
    217                                             int from, int to) const
    218 {
    219     HarfBuzzShaper shaper(this, run);
    220     if (!shaper.shape())
    221         return FloatRect();
    222     return shaper.selectionRect(point, height, from, to);
    223 }
    224 
    225 } // namespace WebCore
    226