1ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien/* 2ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * Copyright (C) 2013 The Android Open Source Project 3ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * 4ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * Licensed under the Apache License, Version 2.0 (the "License"); 5ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * you may not use this file except in compliance with the License. 6ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * You may obtain a copy of the License at 7ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * 8ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * http://www.apache.org/licenses/LICENSE-2.0 9ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * 10ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * Unless required by applicable law or agreed to in writing, software 11ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * distributed under the License is distributed on an "AS IS" BASIS, 12ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * See the License for the specific language governing permissions and 14ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien * limitations under the License. 15ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien */ 16ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 17ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien// This is a test program that uses Minikin to layout and draw some text. 18ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien// At the moment, it just draws a string into /data/local/tmp/foo.pgm. 19ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 20ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <stdio.h> 21ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <vector> 22ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <fstream> 23ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 24ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <unicode/unistr.h> 25ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <unicode/utf16.h> 26ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 27ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <minikin/MinikinFontFreeType.h> 28ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <minikin/Layout.h> 29ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 30ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <SkCanvas.h> 31ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <SkGraphics.h> 32ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <SkImageEncoder.h> 33ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <SkTypeface.h> 34ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <SkPaint.h> 35ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 36ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include "MinikinSkia.h" 37ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 38ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levienusing std::vector; 39ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 40ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Leviennamespace android { 41ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 42ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph LevienFT_Library library; // TODO: this should not be a global 43ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 44ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph LevienFontCollection *makeFontCollection() { 45ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien vector<FontFamily *>typefaces; 46ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien const char *fns[] = { 47ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien "/system/fonts/Roboto-Regular.ttf", 48ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien "/system/fonts/Roboto-Italic.ttf", 49ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien "/system/fonts/Roboto-BoldItalic.ttf", 50ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien "/system/fonts/Roboto-Light.ttf", 51ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien "/system/fonts/Roboto-Thin.ttf", 52ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien "/system/fonts/Roboto-Bold.ttf", 53ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien "/system/fonts/Roboto-ThinItalic.ttf", 54ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien "/system/fonts/Roboto-LightItalic.ttf" 55ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien }; 56ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 57ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien FontFamily *family = new FontFamily(); 58ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) { 59ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien const char *fn = fns[i]; 60ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkTypeface *skFace = SkTypeface::CreateFromFile(fn); 61ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien MinikinFont *font = new MinikinFontSkia(skFace); 62ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien family->addFont(font); 63ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 64ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien typefaces.push_back(family); 65ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 66ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#if 1 67ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien family = new FontFamily(); 68ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien const char *fn = "/system/fonts/DroidSansDevanagari-Regular.ttf"; 69ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkTypeface *skFace = SkTypeface::CreateFromFile(fn); 70ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien MinikinFont *font = new MinikinFontSkia(skFace); 71ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien family->addFont(font); 72ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien typefaces.push_back(family); 73ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#endif 74ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 75ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien return new FontCollection(typefaces); 76ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien} 77ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 78ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien// Maybe move to MinikinSkia (esp. instead of opening GetSkTypeface publicly)? 79ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 80ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levienvoid drawToSkia(SkCanvas *canvas, SkPaint *paint, Layout *layout, float x, float y) { 81ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien size_t nGlyphs = layout->nGlyphs(); 82ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien uint16_t *glyphs = new uint16_t[nGlyphs]; 83ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkPoint *pos = new SkPoint[nGlyphs]; 84ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkTypeface *lastFace = NULL; 85ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkTypeface *skFace = NULL; 86ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien size_t start = 0; 87ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 88ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 89ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien for (size_t i = 0; i < nGlyphs; i++) { 90ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien MinikinFontSkia *mfs = static_cast<MinikinFontSkia *>(layout->getFont(i)); 91ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien skFace = mfs->GetSkTypeface(); 92ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien glyphs[i] = layout->getGlyphId(i); 93a3998d4f51e862f00b3dc6b8b99cfbeea2622b2dLeon Scroggins III pos[i].fX = x + layout->getX(i); 94a3998d4f51e862f00b3dc6b8b99cfbeea2622b2dLeon Scroggins III pos[i].fY = y + layout->getY(i); 95ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien if (i > 0 && skFace != lastFace) { 96ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint->setTypeface(lastFace); 97ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien canvas->drawPosText(glyphs + start, (i - start) << 1, pos + start, *paint); 98ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien start = i; 99ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 100ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien lastFace = skFace; 101ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 102ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint->setTypeface(skFace); 103ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien canvas->drawPosText(glyphs + start, (nGlyphs - start) << 1, pos + start, *paint); 104ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien delete[] glyphs; 105ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien delete[] pos; 106ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien} 107ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 108ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levienint runMinikinTest() { 109ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien FT_Error error = FT_Init_FreeType(&library); 110ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien if (error) { 111ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien return -1; 112ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien } 113ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien Layout::init(); 114ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 115ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien FontCollection *collection = makeFontCollection(); 116ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien Layout layout; 117ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien layout.setFontCollection(collection); 118ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien const char *text = "fine world \xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\xa4\xe0\xa5\x87"; 1199802b0dc8e648117ab917e716e81e8a0da909cb3Behdad Esfahbod int bidiFlags = 0; 1209802b0dc8e648117ab917e716e81e8a0da909cb3Behdad Esfahbod FontStyle fontStyle(7); 1219802b0dc8e648117ab917e716e81e8a0da909cb3Behdad Esfahbod MinikinPaint minikinPaint; 1229802b0dc8e648117ab917e716e81e8a0da909cb3Behdad Esfahbod minikinPaint.size = 32; 123ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien icu::UnicodeString icuText = icu::UnicodeString::fromUTF8(text); 1249802b0dc8e648117ab917e716e81e8a0da909cb3Behdad Esfahbod layout.doLayout(icuText.getBuffer(), 0, icuText.length(), icuText.length(), bidiFlags, fontStyle, minikinPaint); 125ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien layout.dump(); 126ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 127ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkAutoGraphics ag; 128ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 129f8134eff0007533f213925d3e8e37d213b3afdeeMike Reed int width = 800; 130f8134eff0007533f213925d3e8e37d213b3afdeeMike Reed int height = 600; 131ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkBitmap bitmap; 132f8134eff0007533f213925d3e8e37d213b3afdeeMike Reed bitmap.allocN32Pixels(width, height); 133ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkCanvas canvas(bitmap); 134ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkPaint paint; 135ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint.setARGB(255, 0, 0, 128); 136ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint.setStyle(SkPaint::kStroke_Style); 137ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint.setStrokeWidth(2); 138ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint.setTextSize(100); 139ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint.setAntiAlias(true); 140ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien canvas.drawLine(10, 300, 10 + layout.getAdvance(), 300, paint); 141ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien paint.setStyle(SkPaint::kFill_Style); 142ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien drawToSkia(&canvas, &paint, &layout, 10, 300); 143ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 144ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien SkImageEncoder::EncodeFile("/data/local/tmp/foo.png", bitmap, SkImageEncoder::kPNG_Type, 100); 145ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien return 0; 146ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien} 147ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 148ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien} 149ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 150ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levienint main(int argc, const char** argv) { 151ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien return android::runMinikinTest(); 152ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien} 153