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