• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
operator ()__anon770528040111::HBFBlobDel19     void operator()(hb_blob_t* b) { hb_blob_destroy(b); }
20 };
21 
stream_to_blob(std::unique_ptr<SkStreamAsset> asset)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 {
operator ()SkShaper::Impl::HBFontDel44         void operator()(hb_font_t* f) { hb_font_destroy(f); }
45     };
46     std::unique_ptr<hb_font_t, HBFontDel> fHarfBuzzFont;
47     struct HBBufDel {
operator ()SkShaper::Impl::HBBufDel48         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 
SkShaper(sk_sp<SkTypeface> tf)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 
~SkShaper()80 SkShaper::~SkShaper() {}
81 
good() const82 bool SkShaper::good() const { return fImpl->fHarfBuzzFont != nullptr; }
83 
shape(SkTextBlobBuilder * builder,const SkPaint & srcPaint,const char * utf8text,size_t textBytes,SkPoint point) const84 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