diff options
author | Raph Levien <raph@google.com> | 2013-07-15 14:19:59 -0700 |
---|---|---|
committer | Raph Levien <raph@google.com> | 2014-05-12 09:08:15 -0700 |
commit | ecc2d34ac23a497988f21e5f415b53c007b9d8c5 (patch) | |
tree | 876b3c943b7841c9600db636738cd0e59b5f2a7c /sample | |
parent | 5adafc0d84d238948b5d257ec5311030ca04271c (diff) | |
download | android_frameworks_minikin-ecc2d34ac23a497988f21e5f415b53c007b9d8c5.tar.gz android_frameworks_minikin-ecc2d34ac23a497988f21e5f415b53c007b9d8c5.tar.bz2 android_frameworks_minikin-ecc2d34ac23a497988f21e5f415b53c007b9d8c5.zip |
A basket of features: itemization, bounds, refcount
This patch improves script run itemization and also exposes metrics
and bounds for layouts. In addition, there is a fair amount of internal
cleanup, including ref counting, and making the MinikinFont abstraction
strong enough to support both FreeType and Skia implementations. There
is also a sample implementation using Skia, in the sample directory.
As part of its functionality, his patch measures the bounds of the
layout and gives access through Layout::GetBounds(). The corresponding
method is not implemented in the FreeType-only implementation of
MinikinFont, so that will probably have to be fixed.
Change-Id: Ib1a3fe9d7c90519ac651fb4aa957848e4bb758ec
Diffstat (limited to 'sample')
-rw-r--r-- | sample/Android.mk | 36 | ||||
-rw-r--r-- | sample/MinikinSkia.cpp | 64 | ||||
-rw-r--r-- | sample/MinikinSkia.h | 26 | ||||
-rw-r--r-- | sample/example_skia.cpp | 152 |
4 files changed, 275 insertions, 3 deletions
diff --git a/sample/Android.mk b/sample/Android.mk index 939aca4..a19019a 100644 --- a/sample/Android.mk +++ b/sample/Android.mk @@ -36,10 +36,40 @@ LOCAL_SHARED_LIBRARIES += \ libicuuc \ libft2 \ libpng \ - libz - -LOCAL_STATIC_LIBRARIES += libminikin + libz \ + libminikin LOCAL_MODULE:= minikin_example include $(BUILD_EXECUTABLE) + + +include $(CLEAR_VARS) +include external/stlport/libstlport.mk + +LOCAL_MODULE_TAG := tests + +LOCAL_C_INCLUDES += \ + external/harfbuzz_ng/src \ + external/freetype/include \ + external/icu4c/common \ + frameworks/minikin/include \ + external/skia/src/core + +LOCAL_SRC_FILES:= example_skia.cpp \ + MinikinSkia.cpp + +LOCAL_SHARED_LIBRARIES += \ + libutils \ + liblog \ + libcutils \ + libstlport \ + libharfbuzz_ng \ + libicuuc \ + libskia \ + libminikin \ + libft2 + +LOCAL_MODULE:= minikin_skia_example + +include $(BUILD_EXECUTABLE) diff --git a/sample/MinikinSkia.cpp b/sample/MinikinSkia.cpp new file mode 100644 index 0000000..d67e59f --- /dev/null +++ b/sample/MinikinSkia.cpp @@ -0,0 +1,64 @@ +#include <SkTypeface.h> +#include <SkPaint.h> + +#include <minikin/MinikinFont.h> +#include "MinikinSkia.h" + +namespace android { + +MinikinFontSkia::MinikinFontSkia(SkTypeface *typeface) : + mTypeface(typeface) { +} + +MinikinFontSkia::~MinikinFontSkia() { + SkSafeUnref(mTypeface); +} + +bool MinikinFontSkia::GetGlyph(uint32_t codepoint, uint32_t *glyph) const { + SkPaint paint; + paint.setTypeface(mTypeface); + paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); + uint16_t glyph16; + paint.textToGlyphs(&codepoint, sizeof(codepoint), &glyph16); + *glyph = glyph16; + //printf("glyph for U+%04x = %d\n", codepoint, glyph16); + return !!glyph; +} + +float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id, + const MinikinPaint &paint) const { + SkPaint skpaint; + skpaint.setTypeface(mTypeface); + skpaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + // TODO: set paint from Minikin + skpaint.setTextSize(100); + uint16_t glyph16 = glyph_id; + SkScalar skWidth; + SkRect skBounds; + skpaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, &skBounds); + // bounds? + //printf("advance for glyph %d = %f\n", glyph_id, SkScalarToFP(skWidth)); + return skWidth; +} + +bool MinikinFontSkia::GetTable(uint32_t tag, uint8_t *buf, size_t *size) { + if (buf == NULL) { + const size_t tableSize = mTypeface->getTableSize(tag); + *size = tableSize; + return tableSize != 0; + } else { + const size_t actualSize = mTypeface->getTableData(tag, 0, *size, buf); + *size = actualSize; + return actualSize != 0; + } +} + +SkTypeface *MinikinFontSkia::GetSkTypeface() { + return mTypeface; +} + +int32_t MinikinFontSkia::GetUniqueId() const { + return mTypeface->uniqueID(); +} + +} diff --git a/sample/MinikinSkia.h b/sample/MinikinSkia.h new file mode 100644 index 0000000..8286a4c --- /dev/null +++ b/sample/MinikinSkia.h @@ -0,0 +1,26 @@ +namespace android { + +class MinikinFontSkia : public MinikinFont { +public: + explicit MinikinFontSkia(SkTypeface *typeface); + + ~MinikinFontSkia(); + + bool GetGlyph(uint32_t codepoint, uint32_t *glyph) const; + + float GetHorizontalAdvance(uint32_t glyph_id, + const MinikinPaint &paint) const; + + // If buf is NULL, just update size + bool GetTable(uint32_t tag, uint8_t *buf, size_t *size); + + int32_t GetUniqueId() const; + + SkTypeface *GetSkTypeface(); + +private: + SkTypeface *mTypeface; + +}; + +} // namespace android
\ No newline at end of file diff --git a/sample/example_skia.cpp b/sample/example_skia.cpp new file mode 100644 index 0000000..ff13b5c --- /dev/null +++ b/sample/example_skia.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This is a test program that uses Minikin to layout and draw some text. +// At the moment, it just draws a string into /data/local/tmp/foo.pgm. + +#include <stdio.h> +#include <vector> +#include <fstream> + +#include <unicode/unistr.h> +#include <unicode/utf16.h> + +#include <minikin/MinikinFontFreeType.h> +#include <minikin/Layout.h> + +#include <SkCanvas.h> +#include <SkGraphics.h> +#include <SkImageEncoder.h> +#include <SkTypeface.h> +#include <SkPaint.h> + +#include "MinikinSkia.h" + +using std::vector; + +namespace android { + +FT_Library library; // TODO: this should not be a global + +FontCollection *makeFontCollection() { + vector<FontFamily *>typefaces; + const char *fns[] = { + "/system/fonts/Roboto-Regular.ttf", + "/system/fonts/Roboto-Italic.ttf", + "/system/fonts/Roboto-BoldItalic.ttf", + "/system/fonts/Roboto-Light.ttf", + "/system/fonts/Roboto-Thin.ttf", + "/system/fonts/Roboto-Bold.ttf", + "/system/fonts/Roboto-ThinItalic.ttf", + "/system/fonts/Roboto-LightItalic.ttf" + }; + + FontFamily *family = new FontFamily(); + FT_Face face; + FT_Error error; + for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) { + const char *fn = fns[i]; + SkTypeface *skFace = SkTypeface::CreateFromFile(fn); + MinikinFont *font = new MinikinFontSkia(skFace); + family->addFont(font); + } + typefaces.push_back(family); + +#if 1 + family = new FontFamily(); + const char *fn = "/system/fonts/DroidSansDevanagari-Regular.ttf"; + SkTypeface *skFace = SkTypeface::CreateFromFile(fn); + MinikinFont *font = new MinikinFontSkia(skFace); + family->addFont(font); + typefaces.push_back(family); +#endif + + return new FontCollection(typefaces); +} + +// Maybe move to MinikinSkia (esp. instead of opening GetSkTypeface publicly)? + +void drawToSkia(SkCanvas *canvas, SkPaint *paint, Layout *layout, float x, float y) { + size_t nGlyphs = layout->nGlyphs(); + uint16_t *glyphs = new uint16_t[nGlyphs]; + SkPoint *pos = new SkPoint[nGlyphs]; + SkTypeface *lastFace = NULL; + SkTypeface *skFace = NULL; + size_t start = 0; + + paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); + for (size_t i = 0; i < nGlyphs; i++) { + MinikinFontSkia *mfs = static_cast<MinikinFontSkia *>(layout->getFont(i)); + skFace = mfs->GetSkTypeface(); + glyphs[i] = layout->getGlyphId(i); + pos[i].fX = SkFloatToScalar(x + layout->getX(i)); + pos[i].fY = SkFloatToScalar(y + layout->getY(i)); + if (i > 0 && skFace != lastFace) { + paint->setTypeface(lastFace); + canvas->drawPosText(glyphs + start, (i - start) << 1, pos + start, *paint); + start = i; + } + lastFace = skFace; + } + paint->setTypeface(skFace); + canvas->drawPosText(glyphs + start, (nGlyphs - start) << 1, pos + start, *paint); + delete[] glyphs; + delete[] pos; +} + +int runMinikinTest() { + FT_Error error = FT_Init_FreeType(&library); + if (error) { + return -1; + } + Layout::init(); + + FontCollection *collection = makeFontCollection(); + Layout layout; + layout.setFontCollection(collection); + layout.setProperties("font-size: 32; font-weight: 700;"); + const char *text = "fine world \xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\xa4\xe0\xa5\x87"; + icu::UnicodeString icuText = icu::UnicodeString::fromUTF8(text); + layout.doLayout(icuText.getBuffer(), icuText.length()); + layout.dump(); + + SkAutoGraphics ag; + + SkScalar width = 800; + SkScalar height = 600; + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); + bitmap.allocPixels(); + SkCanvas canvas(bitmap); + SkPaint paint; + paint.setARGB(255, 0, 0, 128); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(2); + paint.setTextSize(100); + paint.setAntiAlias(true); + canvas.drawLine(10, 300, 10 + layout.getAdvance(), 300, paint); + paint.setStyle(SkPaint::kFill_Style); + drawToSkia(&canvas, &paint, &layout, 10, 300); + + SkImageEncoder::EncodeFile("/data/local/tmp/foo.png", bitmap, SkImageEncoder::kPNG_Type, 100); + return 0; +} + +} + +int main(int argc, const char** argv) { + return android::runMinikinTest(); +} |