blob: 9c7d69e92d205f6ea190c899778c4b94fe27de48 [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()) {
halcanary13cba492016-08-03 10:43:55 -070026 blob.reset(hb_blob_create((char*)base, SkToUInt(size),
halcanaryf1197962016-07-12 09:17:43 -070027 HB_MEMORY_MODE_READONLY, asset.release(),
28 [](void* p) { delete (SkStreamAsset*)p; }));
29 } else {
30 // SkDebugf("Extra SkStreamAsset copy\n");
Hal Canary95e3c052017-01-11 12:44:43 -050031 void* ptr = size ? sk_malloc_throw(size) : nullptr;
32 asset->read(ptr, size);
33 blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
halcanaryf1197962016-07-12 09:17:43 -070034 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
halcanary8a74f132016-07-11 14:30:39 -070042struct 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
54SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
55 fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
56 int index;
halcanaryf1197962016-07-12 09:17:43 -070057 std::unique_ptr<hb_blob_t, HBFBlobDel> blob(
58 stream_to_blob(std::unique_ptr<SkStreamAsset>(
59 fImpl->fTypeface->openStream(&index))));
halcanary8a74f132016-07-11 14:30:39 -070060 struct HBFaceDel {
61 void operator()(hb_face_t* f) { hb_face_destroy(f); }
62 };
halcanaryf1197962016-07-12 09:17:43 -070063 std::unique_ptr<hb_face_t, HBFaceDel> face(
64 hb_face_create(blob.get(), (unsigned)index));
halcanary8a74f132016-07-11 14:30:39 -070065 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
80SkShaper::~SkShaper() {}
81
82bool SkShaper::good() const { return fImpl->fHarfBuzzFont != nullptr; }
83
84SkScalar 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);
halcanary4f0a23a2016-08-30 11:58:33 -0700107 auto runBuffer = builder->allocRunTextPos(
108 paint, SkToInt(len), SkToInt(textBytes), SkString());
109 memcpy(runBuffer.utf8text, utf8text, textBytes);
halcanary8a74f132016-07-11 14:30:39 -0700110
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;
halcanary4f0a23a2016-08-30 11:58:33 -0700119 runBuffer.clusters[i] = info[i].cluster;
halcanary8a74f132016-07-11 14:30:39 -0700120 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
halcanary13cba492016-08-03 10:43:55 -0700121 SkPoint::Make(SkDoubleToScalar(x + pos[i].x_offset * textSizeX),
122 SkDoubleToScalar(y - pos[i].y_offset * textSizeY));
halcanary8a74f132016-07-11 14:30:39 -0700123 x += pos[i].x_advance * textSizeX;
124 y += pos[i].y_advance * textSizeY;
125 }
halcanary4f0a23a2016-08-30 11:58:33 -0700126
halcanary8a74f132016-07-11 14:30:39 -0700127 hb_buffer_clear_contents(buffer);
128 return (SkScalar)x;
129}