Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include <hb-ot.h>
      9 
     10 #include "SkShaper.h"
     11 #include "SkStream.h"
     12 #include "SkTextBlob.h"
     13 #include "SkTypeface.h"
     14 
     15 static const int FONT_SIZE_SCALE = 512;
     16 
     17 namespace {
     18 struct HBFBlobDel {
     19     void operator()(hb_blob_t* b) { hb_blob_destroy(b); }
     20 };
     21 
     22 std::unique_ptr<hb_blob_t, HBFBlobDel> stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
     23     size_t size = asset->getLength();
     24     std::unique_ptr<hb_blob_t, HBFBlobDel> blob;
     25     if (const void* base = asset->getMemoryBase()) {
     26         blob.reset(hb_blob_create((char*)base, SkToUInt(size),
     27                                   HB_MEMORY_MODE_READONLY, asset.release(),
     28                                   [](void* p) { delete (SkStreamAsset*)p; }));
     29     } else {
     30         // SkDebugf("Extra SkStreamAsset copy\n");
     31         void* ptr = size ? sk_malloc_throw(size) : nullptr;
     32         asset->read(ptr, size);
     33         blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
     34                                   HB_MEMORY_MODE_READONLY, ptr, sk_free));
     35     }
     36     SkASSERT(blob);
     37     hb_blob_make_immutable(blob.get());
     38     return blob;
     39 }
     40 }  // namespace
     41 
     42 struct SkShaper::Impl {
     43     struct HBFontDel {
     44         void operator()(hb_font_t* f) { hb_font_destroy(f); }
     45     };
     46     std::unique_ptr<hb_font_t, HBFontDel> fHarfBuzzFont;
     47     struct HBBufDel {
     48         void operator()(hb_buffer_t* b) { hb_buffer_destroy(b); }
     49     };
     50     std::unique_ptr<hb_buffer_t, HBBufDel> fBuffer;
     51     sk_sp<SkTypeface> fTypeface;
     52 };
     53 
     54 SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
     55     fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
     56     int index;
     57     std::unique_ptr<hb_blob_t, HBFBlobDel> blob(
     58             stream_to_blob(std::unique_ptr<SkStreamAsset>(
     59                                    fImpl->fTypeface->openStream(&index))));
     60     struct HBFaceDel {
     61         void operator()(hb_face_t* f) { hb_face_destroy(f); }
     62     };
     63     std::unique_ptr<hb_face_t, HBFaceDel> face(
     64             hb_face_create(blob.get(), (unsigned)index));
     65     SkASSERT(face);
     66     if (!face) {
     67         return;
     68     }
     69     hb_face_set_index(face.get(), (unsigned)index);
     70     hb_face_set_upem(face.get(), fImpl->fTypeface->getUnitsPerEm());
     71 
     72     fImpl->fHarfBuzzFont.reset(hb_font_create(face.get()));
     73     SkASSERT(fImpl->fHarfBuzzFont);
     74     hb_font_set_scale(fImpl->fHarfBuzzFont.get(), FONT_SIZE_SCALE, FONT_SIZE_SCALE);
     75     hb_ot_font_set_funcs(fImpl->fHarfBuzzFont.get());
     76 
     77     fImpl->fBuffer.reset(hb_buffer_create());
     78 }
     79 
     80 SkShaper::~SkShaper() {}
     81 
     82 bool SkShaper::good() const { return fImpl->fHarfBuzzFont != nullptr; }
     83 
     84 SkScalar SkShaper::shape(SkTextBlobBuilder* builder,
     85                          const SkPaint& srcPaint,
     86                          const char* utf8text,
     87                          size_t textBytes,
     88                          SkPoint point) const {
     89     SkPaint paint(srcPaint);
     90     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
     91     paint.setTypeface(fImpl->fTypeface);
     92 
     93     SkASSERT(builder);
     94     hb_buffer_t* buffer = fImpl->fBuffer.get();
     95     hb_buffer_add_utf8(buffer, utf8text, -1, 0, -1);
     96     hb_buffer_guess_segment_properties(buffer);
     97     hb_shape(fImpl->fHarfBuzzFont.get(), buffer, nullptr, 0);
     98     unsigned len = hb_buffer_get_length(buffer);
     99     if (len == 0) {
    100         hb_buffer_clear_contents(buffer);
    101         return 0;
    102     }
    103 
    104     hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, NULL);
    105     hb_glyph_position_t* pos =
    106             hb_buffer_get_glyph_positions(buffer, NULL);
    107     auto runBuffer = builder->allocRunTextPos(
    108             paint, SkToInt(len), SkToInt(textBytes), SkString());
    109     memcpy(runBuffer.utf8text, utf8text, textBytes);
    110 
    111     double x = point.x();
    112     double y = point.y();
    113 
    114     double textSizeY = paint.getTextSize() / (double)FONT_SIZE_SCALE;
    115     double textSizeX = textSizeY * paint.getTextScaleX();
    116 
    117     for (unsigned i = 0; i < len; i++) {
    118         runBuffer.glyphs[i] = info[i].codepoint;
    119         runBuffer.clusters[i] = info[i].cluster;
    120         reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
    121                 SkPoint::Make(SkDoubleToScalar(x + pos[i].x_offset * textSizeX),
    122                               SkDoubleToScalar(y - pos[i].y_offset * textSizeY));
    123         x += pos[i].x_advance * textSizeX;
    124         y += pos[i].y_advance * textSizeY;
    125     }
    126 
    127     hb_buffer_clear_contents(buffer);
    128     return (SkScalar)x;
    129 }
    130