Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright 2009, The Android Open Source Project
      3  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      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 copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 
     29 #include "EmojiFont.h"
     30 #include "Font.h"
     31 #include "FontData.h"
     32 #include "FontFallbackList.h"
     33 #include "GraphicsContext.h"
     34 #include "GlyphBuffer.h"
     35 #include "IntRect.h"
     36 #include "PlatformGraphicsContext.h"
     37 #include "SkCanvas.h"
     38 #include "SkLayerDrawLooper.h"
     39 #include "SkPaint.h"
     40 #include "SkTemplates.h"
     41 #include "SkTypeface.h"
     42 #include "SkUtils.h"
     43 
     44 using namespace android;
     45 
     46 namespace WebCore {
     47 
     48 static void updateForFont(SkPaint* paint, const SimpleFontData* font) {
     49     font->platformData().setupPaint(paint);
     50     paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
     51 }
     52 
     53 static SkPaint* setupFill(SkPaint* paint, GraphicsContext* gc,
     54                           const SimpleFontData* font) {
     55     gc->setupFillPaint(paint);
     56     updateForFont(paint, font);
     57     return paint;
     58 }
     59 
     60 static SkPaint* setupStroke(SkPaint* paint, GraphicsContext* gc,
     61                             const SimpleFontData* font) {
     62     gc->setupStrokePaint(paint);
     63     updateForFont(paint, font);
     64     return paint;
     65 }
     66 
     67 static bool setupForText(SkPaint* paint, GraphicsContext* gc,
     68                          const SimpleFontData* font) {
     69     int mode = gc->textDrawingMode();
     70 
     71     if ((mode & (cTextFill | cTextStroke)) == (cTextFill | cTextStroke)) {
     72         SkLayerDrawLooper* looper = new SkLayerDrawLooper;
     73         paint->setLooper(looper)->unref();
     74 
     75         // we clear the looper, in case we have a shadow
     76 
     77         SkPaint* fillP = NULL;
     78         SkPaint* strokeP = NULL;
     79         if (gc->willStroke()) {
     80             strokeP = setupStroke(looper->addLayer(), gc, font);
     81             strokeP->setLooper(NULL);
     82         }
     83         if (gc->willFill()) {
     84             fillP = setupFill(looper->addLayer(), gc, font);
     85             fillP->setLooper(NULL);
     86         }
     87 
     88         SkPaint shadowPaint;
     89         SkPoint offset;
     90         if (gc->setupShadowPaint(&shadowPaint, &offset)) {
     91             SkPaint* p = looper->addLayer(offset.fX, offset.fY);
     92             *p = shadowPaint;
     93             if (strokeP && !fillP) {
     94                 // stroke the shadow if we have stroke but no fill
     95                 p->setStyle(SkPaint::kStroke_Style);
     96                 p->setStrokeWidth(strokeP->getStrokeWidth());
     97             }
     98             updateForFont(p, font);
     99         }
    100     } else if (mode & cTextFill) {
    101         (void)setupFill(paint, gc, font);
    102     } else if (mode & cTextStroke) {
    103         (void)setupStroke(paint, gc, font);
    104     } else {
    105         return false;
    106     }
    107     return true;
    108 }
    109 
    110 bool Font::canReturnFallbackFontsForComplexText()
    111 {
    112     return false;
    113 }
    114 
    115 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
    116                       const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
    117                       const FloatPoint& point) const
    118 {
    119     // compile-time assert
    120     SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t));
    121 
    122     SkPaint paint;
    123     if (!setupForText(&paint, gc, font)) {
    124         return;
    125     }
    126 
    127     SkScalar                    x = SkFloatToScalar(point.x());
    128     SkScalar                    y = SkFloatToScalar(point.y());
    129     const GlyphBufferGlyph*     glyphs = glyphBuffer.glyphs(from);
    130     const GlyphBufferAdvance*   adv = glyphBuffer.advances(from);
    131     SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
    132     SkPoint*                    pos = storage.get();
    133 
    134     SkCanvas* canvas = gc->platformContext()->mCanvas;
    135 
    136     /*  We need an array of [x,y,x,y,x,y,...], but webkit is giving us
    137         point.xy + [width, height, width, height, ...], so we have to convert
    138      */
    139 
    140     if (EmojiFont::IsAvailable()) {
    141         // set filtering, to make scaled images look nice(r)
    142         paint.setFilterBitmap(true);
    143 
    144         int localIndex = 0;
    145         int localCount = 0;
    146         for (int i = 0; i < numGlyphs; i++) {
    147             if (EmojiFont::IsEmojiGlyph(glyphs[i])) {
    148                 if (localCount)
    149                     canvas->drawPosText(&glyphs[localIndex],
    150                                         localCount * sizeof(uint16_t),
    151                                         &pos[localIndex], paint);
    152                 EmojiFont::Draw(canvas, glyphs[i], x, y, paint);
    153                 // reset local index/count track for "real" glyphs
    154                 localCount = 0;
    155                 localIndex = i + 1;
    156             } else {
    157                 pos[i].set(x, y);
    158                 localCount += 1;
    159             }
    160             x += SkFloatToScalar(adv[i].width());
    161             y += SkFloatToScalar(adv[i].height());
    162         }
    163         // draw the last run of glyphs (if any)
    164         if (localCount)
    165             canvas->drawPosText(&glyphs[localIndex],
    166                                 localCount * sizeof(uint16_t),
    167                                 &pos[localIndex], paint);
    168     } else {
    169         for (int i = 0; i < numGlyphs; i++) {
    170             pos[i].set(x, y);
    171             x += SkFloatToScalar(adv[i].width());
    172             y += SkFloatToScalar(adv[i].height());
    173         }
    174         canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint);
    175     }
    176 }
    177 
    178 FloatRect Font::selectionRectForComplexText(const TextRun& run,
    179                                 const IntPoint& point, int h, int, int) const
    180 {
    181     SkPaint              paint;
    182     SkScalar             width, left;
    183     SkPaint::FontMetrics metrics;
    184 
    185     primaryFont()->platformData().setupPaint(&paint);
    186 
    187     width = paint.measureText(run.characters(), run.length() << 1);
    188     SkScalar spacing = paint.getFontMetrics(&metrics);
    189 
    190     return FloatRect(point.x(),
    191                      point.y(),
    192                      roundf(SkScalarToFloat(width)),
    193                      roundf(SkScalarToFloat(spacing)));
    194 }
    195 
    196 void Font::drawComplexText(GraphicsContext* gc, TextRun const& run,
    197                            FloatPoint const& point, int, int) const
    198 {
    199     SkCanvas*   canvas = gc->platformContext()->mCanvas;
    200     SkPaint     paint;
    201 
    202     if (!setupForText(&paint, gc, primaryFont())) {
    203         return;
    204     }
    205 
    206     // go to chars, instead of glyphs, which was set by setupForText()
    207     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
    208 
    209     canvas->drawText(run.characters(), run.length() << 1,
    210                      SkFloatToScalar(point.x()), SkFloatToScalar(point.y()),
    211                      paint);
    212 }
    213 
    214 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const
    215 {
    216     SkPaint paint;
    217 
    218     primaryFont()->platformData().setupPaint(&paint);
    219 
    220 //printf("--------- complext measure %d chars\n", run.to() - run.from());
    221 
    222     SkScalar width = paint.measureText(run.characters(), run.length() << 1);
    223     return SkScalarToFloat(width);
    224 }
    225 
    226 int Font::offsetForPositionForComplexText(const TextRun& run, int x,
    227                                           bool includePartialGlyphs) const
    228 {
    229     SkPaint                         paint;
    230     int                             count = run.length();
    231     SkAutoSTMalloc<64, SkScalar>    storage(count);
    232     SkScalar*                       widths = storage.get();
    233 
    234     primaryFont()->platformData().setupPaint(&paint);
    235 
    236     count = paint.getTextWidths(run.characters(), count << 1, widths);
    237 
    238     if (count > 0)
    239     {
    240         SkScalar pos = 0;
    241         for (int i = 0; i < count; i++)
    242         {
    243             if (x < SkScalarRound(pos + SkScalarHalf(widths[i])))
    244                 return i;
    245             pos += widths[i];
    246         }
    247     }
    248     return count;
    249 }
    250 
    251 }
    252