blob: 44dd8fc7f1bbf0e72c47ffd2c469885ca045d144 [file] [log] [blame]
halcanary8a74f132016-07-11 14:30:39 -07001/*
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
15static const int FONT_SIZE_SCALE = 512;
16
halcanaryf1197962016-07-12 09:17:43 -070017namespace {
18struct HBFBlobDel {
19 void operator()(hb_blob_t* b) { hb_blob_destroy(b); }
20};
21
22std::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, size,
27 HB_MEMORY_MODE_READONLY, asset.release(),
28 [](void* p) { delete (SkStreamAsset*)p; }));
29 } else {
30 // SkDebugf("Extra SkStreamAsset copy\n");
31 SkAutoMalloc autoMalloc(size);
32 asset->read(autoMalloc.get(), size);
33 void* ptr = autoMalloc.get();
34 blob.reset(hb_blob_create((char*)autoMalloc.release(), size,
35 HB_MEMORY_MODE_READONLY, ptr, sk_free));
36 }
37 SkASSERT(blob);
38 hb_blob_make_immutable(blob.get());
39 return blob;
40}
41} // namespace
42
halcanary8a74f132016-07-11 14:30:39 -070043struct SkShaper::Impl {
44 struct HBFontDel {
45 void operator()(hb_font_t* f) { hb_font_destroy(f); }
46 };
47 std::unique_ptr<hb_font_t, HBFontDel> fHarfBuzzFont;
48 struct HBBufDel {
49 void operator()(hb_buffer_t* b) { hb_buffer_destroy(b); }
50 };
51 std::unique_ptr<hb_buffer_t, HBBufDel> fBuffer;
52 sk_sp<SkTypeface> fTypeface;
53};
54
55SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
56 fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
57 int index;
halcanaryf1197962016-07-12 09:17:43 -070058 std::unique_ptr<hb_blob_t, HBFBlobDel> blob(
59 stream_to_blob(std::unique_ptr<SkStreamAsset>(
60 fImpl->fTypeface->openStream(&index))));
halcanary8a74f132016-07-11 14:30:39 -070061 struct HBFaceDel {
62 void operator()(hb_face_t* f) { hb_face_destroy(f); }
63 };
halcanaryf1197962016-07-12 09:17:43 -070064 std::unique_ptr<hb_face_t, HBFaceDel> face(
65 hb_face_create(blob.get(), (unsigned)index));
halcanary8a74f132016-07-11 14:30:39 -070066 SkASSERT(face);
67 if (!face) {
68 return;
69 }
70 hb_face_set_index(face.get(), (unsigned)index);
71 hb_face_set_upem(face.get(), fImpl->fTypeface->getUnitsPerEm());
72
73 fImpl->fHarfBuzzFont.reset(hb_font_create(face.get()));
74 SkASSERT(fImpl->fHarfBuzzFont);
75 hb_font_set_scale(fImpl->fHarfBuzzFont.get(), FONT_SIZE_SCALE, FONT_SIZE_SCALE);
76 hb_ot_font_set_funcs(fImpl->fHarfBuzzFont.get());
77
78 fImpl->fBuffer.reset(hb_buffer_create());
79}
80
81SkShaper::~SkShaper() {}
82
83bool SkShaper::good() const { return fImpl->fHarfBuzzFont != nullptr; }
84
85SkScalar SkShaper::shape(SkTextBlobBuilder* builder,
86 const SkPaint& srcPaint,
87 const char* utf8text,
88 size_t textBytes,
89 SkPoint point) const {
90 SkPaint paint(srcPaint);
91 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
92 paint.setTypeface(fImpl->fTypeface);
93
94 SkASSERT(builder);
95 hb_buffer_t* buffer = fImpl->fBuffer.get();
96 hb_buffer_add_utf8(buffer, utf8text, -1, 0, -1);
97 hb_buffer_guess_segment_properties(buffer);
98 hb_shape(fImpl->fHarfBuzzFont.get(), buffer, nullptr, 0);
99 unsigned len = hb_buffer_get_length(buffer);
100 if (len == 0) {
101 hb_buffer_clear_contents(buffer);
102 return 0;
103 }
104
105 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, NULL);
106 hb_glyph_position_t* pos =
107 hb_buffer_get_glyph_positions(buffer, NULL);
108 auto runBuffer = builder->allocRunPos(paint, len);
109
110 double x = point.x();
111 double y = point.y();
112
113 double textSizeY = paint.getTextSize() / (double)FONT_SIZE_SCALE;
114 double textSizeX = textSizeY * paint.getTextScaleX();
115
116 for (unsigned i = 0; i < len; i++) {
117 runBuffer.glyphs[i] = info[i].codepoint;
118 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
119 SkPoint::Make(x + pos[i].x_offset * textSizeX,
120 y - pos[i].y_offset * textSizeY);
121 x += pos[i].x_advance * textSizeX;
122 y += pos[i].y_advance * textSizeY;
123 }
124 hb_buffer_clear_contents(buffer);
125 return (SkScalar)x;
126}