Index: tools/SkShaper.cpp |
diff --git a/tools/SkShaper.cpp b/tools/SkShaper.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..377f07c109d5ba69681b5d891c16e55ddcc4782b |
--- /dev/null |
+++ b/tools/SkShaper.cpp |
@@ -0,0 +1,108 @@ |
+/* |
+ * Copyright 2016 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include <hb-ot.h> |
+ |
+#include "SkShaper.h" |
+#include "SkStream.h" |
+#include "SkTextBlob.h" |
+#include "SkTypeface.h" |
+ |
+static const int FONT_SIZE_SCALE = 512; |
+ |
+struct SkShaper::Impl { |
+ struct HBFontDel { |
+ void operator()(hb_font_t* f) { hb_font_destroy(f); } |
+ }; |
+ std::unique_ptr<hb_font_t, HBFontDel> fHarfBuzzFont; |
+ struct HBBufDel { |
+ void operator()(hb_buffer_t* b) { hb_buffer_destroy(b); } |
+ }; |
+ std::unique_ptr<hb_buffer_t, HBBufDel> fBuffer; |
+ sk_sp<SkTypeface> fTypeface; |
+}; |
+ |
+SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) { |
+ fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault(); |
+ int index; |
+ std::unique_ptr<SkStreamAsset> asset(fImpl->fTypeface->openStream(&index)); |
+ size_t size = asset->getLength(); |
+ SkAutoMalloc autoMalloc(size); // TODO(halcanary): Avoid this malloc+copy. |
+ asset->read(autoMalloc.get(), size); |
+ asset = nullptr; |
+ void* ptr = autoMalloc.get(); |
+ hb_blob_t* blob = hb_blob_create((char*)autoMalloc.release(), size, |
+ HB_MEMORY_MODE_READONLY, ptr, sk_free); |
+ SkASSERT(blob); |
+ hb_blob_make_immutable(blob); |
+ |
+ struct HBFaceDel { |
+ void operator()(hb_face_t* f) { hb_face_destroy(f); } |
+ }; |
+ std::unique_ptr<hb_face_t, HBFaceDel> face(hb_face_create(blob, (unsigned)index)); |
+ hb_blob_destroy(blob); |
+ SkASSERT(face); |
+ if (!face) { |
+ return; |
+ } |
+ hb_face_set_index(face.get(), (unsigned)index); |
+ hb_face_set_upem(face.get(), fImpl->fTypeface->getUnitsPerEm()); |
+ |
+ fImpl->fHarfBuzzFont.reset(hb_font_create(face.get())); |
+ SkASSERT(fImpl->fHarfBuzzFont); |
+ hb_font_set_scale(fImpl->fHarfBuzzFont.get(), FONT_SIZE_SCALE, FONT_SIZE_SCALE); |
+ hb_ot_font_set_funcs(fImpl->fHarfBuzzFont.get()); |
+ |
+ fImpl->fBuffer.reset(hb_buffer_create()); |
+} |
+ |
+SkShaper::~SkShaper() {} |
+ |
+bool SkShaper::good() const { return fImpl->fHarfBuzzFont != nullptr; } |
+ |
+SkScalar SkShaper::shape(SkTextBlobBuilder* builder, |
+ const SkPaint& srcPaint, |
+ const char* utf8text, |
+ size_t textBytes, |
+ SkPoint point) const { |
+ SkPaint paint(srcPaint); |
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
+ paint.setTypeface(fImpl->fTypeface); |
+ |
+ SkASSERT(builder); |
+ hb_buffer_t* buffer = fImpl->fBuffer.get(); |
+ hb_buffer_add_utf8(buffer, utf8text, -1, 0, -1); |
+ hb_buffer_guess_segment_properties(buffer); |
+ hb_shape(fImpl->fHarfBuzzFont.get(), buffer, nullptr, 0); |
+ unsigned len = hb_buffer_get_length(buffer); |
+ if (len == 0) { |
+ hb_buffer_clear_contents(buffer); |
+ return 0; |
+ } |
+ |
+ hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, NULL); |
+ hb_glyph_position_t* pos = |
+ hb_buffer_get_glyph_positions(buffer, NULL); |
+ auto runBuffer = builder->allocRunPos(paint, len); |
+ |
+ double x = point.x(); |
+ double y = point.y(); |
+ |
+ double textSizeY = paint.getTextSize() / (double)FONT_SIZE_SCALE; |
+ double textSizeX = textSizeY * paint.getTextScaleX(); |
+ |
+ for (unsigned i = 0; i < len; i++) { |
+ runBuffer.glyphs[i] = info[i].codepoint; |
+ reinterpret_cast<SkPoint*>(runBuffer.pos)[i] = |
+ SkPoint::Make(x + pos[i].x_offset * textSizeX, |
+ y - pos[i].y_offset * textSizeY); |
+ x += pos[i].x_advance * textSizeX; |
+ y += pos[i].y_advance * textSizeY; |
+ } |
+ hb_buffer_clear_contents(buffer); |
+ return (SkScalar)x; |
+} |