Home | History | Annotate | Download | only in ports
      1 /*
      2  * Copyright 2006-2012 The Android Open Source Project
      3  * Copyright 2012 Mozilla Foundation
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "SkBitmap.h"
     10 #include "SkCanvas.h"
     11 #include "SkColor.h"
     12 #include "SkColorPriv.h"
     13 #include "SkFDot6.h"
     14 #include "SkFontHost_FreeType_common.h"
     15 #include "SkPath.h"
     16 
     17 #include <ft2build.h>
     18 #include FT_OUTLINE_H
     19 #include FT_BITMAP_H
     20 // In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
     21 #include FT_SYNTHESIS_H
     22 
     23 static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
     24     switch (format) {
     25         case SkMask::kBW_Format:
     26             return FT_PIXEL_MODE_MONO;
     27         case SkMask::kA8_Format:
     28         default:
     29             return FT_PIXEL_MODE_GRAY;
     30     }
     31 }
     32 
     33 ///////////////////////////////////////////////////////////////////////////////
     34 
     35 // hand-tuned value to reduce outline embolden strength
     36 #ifndef SK_OUTLINE_EMBOLDEN_DIVISOR
     37     #ifdef SK_BUILD_FOR_ANDROID
     38         #define SK_OUTLINE_EMBOLDEN_DIVISOR   34
     39     #else
     40         #define SK_OUTLINE_EMBOLDEN_DIVISOR   24
     41     #endif
     42 #endif
     43 
     44 ///////////////////////////////////////////////////////////////////////////////
     45 
     46 static uint16_t packTriple(unsigned r, unsigned g, unsigned b) {
     47     return SkPackRGB16(r >> 3, g >> 2, b >> 3);
     48 }
     49 
     50 static uint16_t grayToRGB16(U8CPU gray) {
     51     SkASSERT(gray <= 255);
     52     return SkPackRGB16(gray >> 3, gray >> 2, gray >> 3);
     53 }
     54 
     55 static int bittst(const uint8_t data[], int bitOffset) {
     56     SkASSERT(bitOffset >= 0);
     57     int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
     58     return lowBit & 1;
     59 }
     60 
     61 template<bool APPLY_PREBLEND>
     62 static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap,
     63                          int lcdIsBGR, bool lcdIsVert, const uint8_t* tableR,
     64                          const uint8_t* tableG, const uint8_t* tableB) {
     65     if (lcdIsVert) {
     66         SkASSERT(3 * glyph.fHeight == bitmap.rows);
     67     } else {
     68         SkASSERT(glyph.fHeight == bitmap.rows);
     69     }
     70 
     71     uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
     72     const size_t dstRB = glyph.rowBytes();
     73     const int width = glyph.fWidth;
     74     const uint8_t* src = bitmap.buffer;
     75 
     76     switch (bitmap.pixel_mode) {
     77         case FT_PIXEL_MODE_MONO:
     78             for (int y = 0; y < glyph.fHeight; ++y) {
     79                 for (int x = 0; x < width; ++x) {
     80                     dst[x] = -bittst(src, x);
     81                 }
     82                 dst = (uint16_t*)((char*)dst + dstRB);
     83                 src += bitmap.pitch;
     84             }
     85             break;
     86         case FT_PIXEL_MODE_GRAY:
     87             for (int y = 0; y < glyph.fHeight; ++y) {
     88                 for (int x = 0; x < width; ++x) {
     89                     dst[x] = grayToRGB16(src[x]);
     90                 }
     91                 dst = (uint16_t*)((char*)dst + dstRB);
     92                 src += bitmap.pitch;
     93             }
     94             break;
     95         default:
     96             SkASSERT(lcdIsVert || (glyph.fWidth * 3 == bitmap.width));
     97             for (int y = 0; y < glyph.fHeight; y++) {
     98                 if (lcdIsVert) {    // vertical stripes
     99                     const uint8_t* srcR = src;
    100                     const uint8_t* srcG = srcR + bitmap.pitch;
    101                     const uint8_t* srcB = srcG + bitmap.pitch;
    102                     if (lcdIsBGR) {
    103                         SkTSwap(srcR, srcB);
    104                     }
    105                     for (int x = 0; x < width; x++) {
    106                         dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR),
    107                                             sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG),
    108                                             sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB));
    109                     }
    110                     src += 3 * bitmap.pitch;
    111                 } else {            // horizontal stripes
    112                     const uint8_t* triple = src;
    113                     if (lcdIsBGR) {
    114                         for (int x = 0; x < width; x++) {
    115                             dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR),
    116                                                 sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
    117                                                 sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB));
    118                             triple += 3;
    119                         }
    120                     } else {
    121                         for (int x = 0; x < width; x++) {
    122                             dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR),
    123                                                 sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG),
    124                                                 sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB));
    125                             triple += 3;
    126                         }
    127                     }
    128                     src += bitmap.pitch;
    129                 }
    130                 dst = (uint16_t*)((char*)dst + dstRB);
    131             }
    132             break;
    133     }
    134 }
    135 
    136 // copies an FT_Bitmap's pixel data into a buffer with identical dimensions
    137 static void copyFTBitmap(const FT_Bitmap& srcFTBitmap, uint8_t* dst, uint8_t dstFormat,
    138                          size_t dstRowBytes) {
    139     const uint8_t* src = reinterpret_cast<const uint8_t*>(srcFTBitmap.buffer);
    140     size_t width = srcFTBitmap.width;
    141     size_t height = srcFTBitmap.rows;
    142     size_t srcRowBytes = srcFTBitmap.pitch;
    143 
    144     if ((SkMask::kA8_Format == dstFormat &&
    145          FT_PIXEL_MODE_GRAY == srcFTBitmap.pixel_mode) ||
    146         (SkMask::kBW_Format == dstFormat &&
    147          FT_PIXEL_MODE_MONO == srcFTBitmap.pixel_mode)) {
    148         // TODO: test 1bpp bitmap font into kBW_Format glyph
    149         size_t minRowBytes = SkMin32(srcRowBytes, dstRowBytes);
    150         size_t extraRowBytes = dstRowBytes - minRowBytes;
    151         for (int y = height - 1; y >= 0; --y) {
    152             memcpy(dst, src, minRowBytes);
    153             memset(dst + minRowBytes, 0, extraRowBytes);
    154             src += srcRowBytes;
    155             dst += dstRowBytes;
    156         }
    157     } else if (SkMask::kA8_Format == dstFormat &&
    158                FT_PIXEL_MODE_MONO == srcFTBitmap.pixel_mode) {
    159         // TODO: test 1bpp bitmap font into kA8_Format glyph
    160         for (size_t y = 0; y < height; ++y) {
    161             uint8_t byte = 0;
    162             int bits = 0;
    163             const uint8_t* src_row = src;
    164             uint8_t* dst_row = dst;
    165             for (size_t x = 0; x < width; ++x) {
    166                 if (!bits) {
    167                     byte = *src_row++;
    168                     bits = 8;
    169                 }
    170                 *dst_row++ = byte & 0x80 ? 0xff : 0;
    171                 bits--;
    172                 byte <<= 1;
    173             }
    174             src += srcRowBytes;
    175             dst += dstRowBytes;
    176         }
    177 #ifdef FT_LOAD_COLOR
    178     } else if (SkMask::kARGB32_Format == dstFormat &&
    179                FT_PIXEL_MODE_BGRA == srcFTBitmap.pixel_mode) {
    180         size_t minWidth = SkMin32(width, SkMin32(srcRowBytes, dstRowBytes) / 4);
    181         size_t extraRowBytes = dstRowBytes - (4 * minWidth);
    182         for (size_t y = 0; y < height; ++y) {
    183             const uint8_t* src_row = src;
    184             uint8_t* dst_row = dst;
    185             for (size_t x = 0; x < minWidth; ++x) {
    186                 uint8_t blue = *src_row++;
    187                 uint8_t green = *src_row++;
    188                 uint8_t red = *src_row++;
    189                 uint8_t alpha = *src_row++;
    190                 *dst_row++ = red;
    191                 *dst_row++ = green;
    192                 *dst_row++ = blue;
    193                 *dst_row++ = alpha;
    194             }
    195             memset(dst_row, 0, extraRowBytes);
    196             src += srcRowBytes;
    197             dst += dstRowBytes;
    198         }
    199 #endif
    200     } else {
    201         SkDEBUGFAIL("unsupported combination of FT_PIXEL_MODE and SkMask::Format");
    202     }
    203 }
    204 
    205 inline uint8_t skFormatForFTPixelMode(char pixel_mode) {
    206     switch (pixel_mode) {
    207         case FT_PIXEL_MODE_GRAY:
    208             return SkMask::kA8_Format;
    209         case FT_PIXEL_MODE_MONO:
    210             return SkMask::kBW_Format;
    211 #ifdef FT_LOAD_COLOR
    212         case FT_PIXEL_MODE_BGRA:
    213             return SkMask::kARGB32_Format;
    214 #endif
    215         default:
    216             SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
    217             return SkMask::kA8_Format;
    218     }
    219 }
    220 
    221 inline SkBitmap::Config skConfigForFTPixelMode(char pixel_mode) {
    222     switch (pixel_mode) {
    223         case FT_PIXEL_MODE_GRAY:
    224             return SkBitmap::kA8_Config;
    225         case FT_PIXEL_MODE_MONO:
    226             return SkBitmap::kA1_Config;
    227 #ifdef FT_LOAD_COLOR
    228         case FT_PIXEL_MODE_BGRA:
    229             return SkBitmap::kARGB_8888_Config;
    230 #endif
    231         default:
    232             SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
    233             return SkBitmap::kA8_Config;
    234     }
    235 }
    236 
    237 inline SkBitmap::Config skConfigForFormat(uint8_t format) {
    238     switch (format) {
    239         case SkMask::kA8_Format:
    240             return SkBitmap::kA8_Config;
    241         case SkMask::kBW_Format:
    242             return SkBitmap::kA1_Config;
    243 #ifdef FT_LOAD_COLOR
    244         case SkMask::kARGB32_Format:
    245             return SkBitmap::kARGB_8888_Config;
    246 #endif
    247         default:
    248             SkDEBUGFAIL("unsupported FT_PIXEL_MODE");
    249             return SkBitmap::kA8_Config;
    250     }
    251 }
    252 
    253 void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
    254     const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
    255     const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
    256 
    257     switch ( face->glyph->format ) {
    258         case FT_GLYPH_FORMAT_OUTLINE:
    259             {
    260                 FT_Outline* outline = &face->glyph->outline;
    261                 FT_BBox     bbox;
    262                 FT_Bitmap   target;
    263 
    264                 if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
    265                     !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
    266                     emboldenOutline(face, outline);
    267                 }
    268 
    269                 int dx = 0, dy = 0;
    270                 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
    271                     dx = SkFixedToFDot6(glyph.getSubXFixed());
    272                     dy = SkFixedToFDot6(glyph.getSubYFixed());
    273                     // negate dy since freetype-y-goes-up and skia-y-goes-down
    274                     dy = -dy;
    275                 }
    276                 FT_Outline_Get_CBox(outline, &bbox);
    277                 /*
    278                     what we really want to do for subpixel is
    279                         offset(dx, dy)
    280                         compute_bounds
    281                         offset(bbox & !63)
    282                     but that is two calls to offset, so we do the following, which
    283                     achieves the same thing with only one offset call.
    284                 */
    285                 FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
    286                                               dy - ((bbox.yMin + dy) & ~63));
    287 
    288                 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
    289                     FT_Render_Glyph(face->glyph,
    290                                     doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
    291                     if (fPreBlend.isApplicable()) {
    292                         copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
    293                                            fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    294                     } else {
    295                         copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
    296                                             fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    297                     }
    298                 } else {
    299                     target.width = glyph.fWidth;
    300                     target.rows = glyph.fHeight;
    301                     target.pitch = glyph.rowBytes();
    302                     target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
    303                     target.pixel_mode = compute_pixel_mode(
    304                                                     (SkMask::Format)fRec.fMaskFormat);
    305                     target.num_grays = 256;
    306 
    307                     memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
    308                     FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
    309                 }
    310             }
    311             break;
    312 
    313         case FT_GLYPH_FORMAT_BITMAP:
    314             if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
    315                 !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
    316                 FT_GlyphSlot_Own_Bitmap(face->glyph);
    317                 FT_Bitmap_Embolden(face->glyph->library, &face->glyph->bitmap, kBitmapEmboldenStrength, 0);
    318             }
    319 
    320             if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
    321                 // special-case kLCD16_Format - no scaling currently supported
    322                 SkASSERT_CONTINUE(glyph.fWidth == face->glyph->bitmap.width);
    323                 SkASSERT_CONTINUE(glyph.fHeight == face->glyph->bitmap.rows);
    324                 SkASSERT_CONTINUE(glyph.fTop == -face->glyph->bitmap_top);
    325                 SkASSERT_CONTINUE(glyph.fLeft == face->glyph->bitmap_left);
    326                 if (fPreBlend.isApplicable()) {
    327                     copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
    328                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    329                 } else {
    330                     copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
    331                                         fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
    332                 }
    333             } else {
    334                 if (glyph.fWidth != face->glyph->bitmap.width ||
    335                     glyph.fHeight != face->glyph->bitmap.rows ||
    336                     glyph.fTop != -face->glyph->bitmap_top ||
    337                     glyph.fLeft != face->glyph->bitmap_left) {
    338                     // glyph image needs scaling
    339                     // start by copying FT2 image into an SkBitmap
    340                     SkBitmap unscaledBitmap;
    341                     unscaledBitmap.setConfig(skConfigForFTPixelMode(face->glyph->bitmap.pixel_mode),
    342                                              face->glyph->bitmap.width,
    343                                              face->glyph->bitmap.rows);
    344                     unscaledBitmap.allocPixels();
    345                     copyFTBitmap(face->glyph->bitmap,
    346                                  reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels()),
    347                                  skFormatForFTPixelMode(face->glyph->bitmap.pixel_mode),
    348                                  unscaledBitmap.rowBytes());
    349                     // wrap the destination SkGlyph's image data into a bitmap
    350                     SkBitmap dstBitmap;
    351                     dstBitmap.setConfig(skConfigForFormat(glyph.fMaskFormat),
    352                                 glyph.fWidth, glyph.fHeight, glyph.rowBytes());
    353                     dstBitmap.setPixels(glyph.fImage);
    354                     // scale unscaledBitmap into dstBitmap
    355                     SkCanvas canvas(dstBitmap);
    356                     canvas.clear(SK_ColorTRANSPARENT);
    357                     canvas.scale(SkIntToScalar(glyph.fWidth)
    358                                 / SkIntToScalar(face->glyph->bitmap.width),
    359                                 SkIntToScalar(glyph.fHeight)
    360                                 / SkIntToScalar(face->glyph->bitmap.rows));
    361                     SkPaint paint;
    362                     paint.setFilterLevel(SkPaint::kLow_FilterLevel);
    363                     canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);
    364                 } else {
    365                     // no scaling needed - directly copy glyph data
    366                     copyFTBitmap(face->glyph->bitmap, reinterpret_cast<uint8_t*>(glyph.fImage),
    367                                  glyph.fMaskFormat, glyph.rowBytes());
    368                 }
    369             }
    370             break;
    371 
    372         default:
    373             SkDEBUGFAIL("unknown glyph format");
    374             memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
    375             return;
    376     }
    377 
    378 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
    379 // it is optional
    380 #if defined(SK_GAMMA_APPLY_TO_A8)
    381     if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
    382         uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
    383         unsigned rowBytes = glyph.rowBytes();
    384 
    385         for (int y = glyph.fHeight - 1; y >= 0; --y) {
    386             for (int x = glyph.fWidth - 1; x >= 0; --x) {
    387                 dst[x] = fPreBlend.fG[dst[x]];
    388             }
    389             dst += rowBytes;
    390         }
    391     }
    392 #endif
    393 }
    394 
    395 ///////////////////////////////////////////////////////////////////////////////
    396 
    397 static int move_proc(const FT_Vector* pt, void* ctx) {
    398     SkPath* path = (SkPath*)ctx;
    399     path->close();  // to close the previous contour (if any)
    400     path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
    401     return 0;
    402 }
    403 
    404 static int line_proc(const FT_Vector* pt, void* ctx) {
    405     SkPath* path = (SkPath*)ctx;
    406     path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y));
    407     return 0;
    408 }
    409 
    410 static int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1,
    411                      void* ctx) {
    412     SkPath* path = (SkPath*)ctx;
    413     path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
    414                  SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y));
    415     return 0;
    416 }
    417 
    418 static int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1,
    419                       const FT_Vector* pt2, void* ctx) {
    420     SkPath* path = (SkPath*)ctx;
    421     path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y),
    422                   SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y),
    423                   SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y));
    424     return 0;
    425 }
    426 
    427 void SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face,
    428                                                       SkPath* path)
    429 {
    430     if (fRec.fFlags & SkScalerContext::kEmbolden_Flag && !(face->style_flags & FT_STYLE_FLAG_BOLD)) {
    431         emboldenOutline(face, &face->glyph->outline);
    432     }
    433 
    434     FT_Outline_Funcs    funcs;
    435 
    436     funcs.move_to   = move_proc;
    437     funcs.line_to   = line_proc;
    438     funcs.conic_to  = quad_proc;
    439     funcs.cubic_to  = cubic_proc;
    440     funcs.shift     = 0;
    441     funcs.delta     = 0;
    442 
    443     FT_Error err = FT_Outline_Decompose(&face->glyph->outline, &funcs, path);
    444 
    445     if (err != 0) {
    446         path->reset();
    447         return;
    448     }
    449 
    450     path->close();
    451 }
    452 
    453 void SkScalerContext_FreeType_Base::emboldenOutline(FT_Face face, FT_Outline* outline)
    454 {
    455     FT_Pos strength;
    456     strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale)
    457                / SK_OUTLINE_EMBOLDEN_DIVISOR;
    458     FT_Outline_Embolden(outline, strength);
    459 }
    460