Layout.cpp 29.8 KB
Newer Older
R
Raph Levien 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * 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.
 */

17 18 19
#define LOG_TAG "Minikin"
#include <cutils/log.h>

20 21 22
#include <math.h>
#include <stdio.h>  // for debugging

R
Raph Levien 已提交
23
#include <algorithm>
R
Raph Levien 已提交
24 25
#include <fstream>
#include <iostream>  // for debugging
26 27
#include <string>
#include <vector>
R
Raph Levien 已提交
28

29 30 31 32 33
#include <utils/JenkinsHash.h>
#include <utils/LruCache.h>
#include <utils/Singleton.h>
#include <utils/String16.h>

R
Raph Levien 已提交
34
#include <unicode/ubidi.h>
35 36
#include <hb-icu.h>

R
Raph Levien 已提交
37
#include "MinikinInternal.h"
R
Raph Levien 已提交
38
#include <minikin/MinikinFontFreeType.h>
R
Raph Levien 已提交
39 40 41 42 43 44 45
#include <minikin/Layout.h>

using std::string;
using std::vector;

namespace android {

R
Raph Levien 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
// TODO: these should move into the header file, but for now we don't want
// to cause namespace collisions with TextLayout.h
enum {
    kBidi_LTR = 0,
    kBidi_RTL = 1,
    kBidi_Default_LTR = 2,
    kBidi_Default_RTL = 3,
    kBidi_Force_LTR = 4,
    kBidi_Force_RTL = 5,

    kBidi_Mask = 0x7
};

const int kDirection_Mask = 0x1;

B
Behdad Esfahbod 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73
struct LayoutContext {
    MinikinPaint paint;
    FontStyle style;
    std::vector<hb_font_t*> hbFonts;  // parallel to mFaces

    void clearHbFonts() {
        for (size_t i = 0; i < hbFonts.size(); i++) {
            hb_font_destroy(hbFonts[i]);
        }
        hbFonts.clear();
    }
};

74 75 76 77 78 79
// Layout cache datatypes

class LayoutCacheKey {
public:
    LayoutCacheKey(const FontCollection* collection, const MinikinPaint& paint, FontStyle style,
            const uint16_t* chars, size_t start, size_t count, size_t nchars, bool dir)
80 81
            : mChars(chars), mNchars(nchars),
            mStart(start), mCount(count), mId(collection->getId()), mStyle(style),
R
Raph Levien 已提交
82
            mSize(paint.size), mScaleX(paint.scaleX), mSkewX(paint.skewX),
B
Behdad Esfahbod 已提交
83
            mLetterSpacing(paint.letterSpacing),
84
            mPaintFlags(paint.paintFlags), mIsRtl(dir) {
85 86 87 88
    }
    bool operator==(const LayoutCacheKey &other) const;
    hash_t hash() const;

B
Behdad Esfahbod 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    void copyText() {
        uint16_t* charsCopy = new uint16_t[mNchars];
        memcpy(charsCopy, mChars, mNchars * sizeof(uint16_t));
        mChars = charsCopy;
    }
    void freeText() {
        delete[] mChars;
        mChars = NULL;
    }

    void doLayout(Layout* layout, LayoutContext* ctx, const FontCollection* collection) const {
        layout->setFontCollection(collection);
        layout->mAdvances.resize(mCount, 0);
        ctx->clearHbFonts();
        layout->doLayoutRun(mChars, mStart, mCount, mNchars, mIsRtl, ctx);
    }

106
private:
B
Behdad Esfahbod 已提交
107 108
    const uint16_t* mChars;
    size_t mNchars;
109 110 111 112 113
    size_t mStart;
    size_t mCount;
    uint32_t mId;  // for the font collection
    FontStyle mStyle;
    float mSize;
R
Raph Levien 已提交
114 115
    float mScaleX;
    float mSkewX;
B
Behdad Esfahbod 已提交
116
    float mLetterSpacing;
R
Raph Levien 已提交
117
    int32_t mPaintFlags;
118 119 120 121 122 123 124 125 126 127 128
    bool mIsRtl;
    // Note: any fields added to MinikinPaint must also be reflected here.
    // TODO: language matching (possibly integrate into style)
};

class LayoutCache : private OnEntryRemoved<LayoutCacheKey, Layout*> {
public:
    LayoutCache() : mCache(kMaxEntries) {
        mCache.setOnEntryRemovedListener(this);
    }

B
Behdad Esfahbod 已提交
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    void clear() {
        mCache.clear();
    }

    Layout* get(LayoutCacheKey& key, LayoutContext* ctx, const FontCollection* collection) {
        Layout* layout = mCache.get(key);
        if (layout == NULL) {
            key.copyText();
            layout = new Layout();
            key.doLayout(layout, ctx, collection);
            mCache.put(key, layout);
        }
        return layout;
    }

private:
145 146
    // callback for OnEntryRemoved
    void operator()(LayoutCacheKey& key, Layout*& value) {
B
Behdad Esfahbod 已提交
147
        key.freeText();
148 149 150 151
        delete value;
    }

    LruCache<LayoutCacheKey, Layout*> mCache;
B
Behdad Esfahbod 已提交
152

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    //static const size_t kMaxEntries = LruCache<LayoutCacheKey, Layout*>::kUnlimitedCapacity;

    // TODO: eviction based on memory footprint; for now, we just use a constant
    // number of strings
    static const size_t kMaxEntries = 5000;
};

class HbFaceCache : private OnEntryRemoved<int32_t, hb_face_t*> {
public:
    HbFaceCache() : mCache(kMaxEntries) {
        mCache.setOnEntryRemovedListener(this);
    }

    // callback for OnEntryRemoved
    void operator()(int32_t& key, hb_face_t*& value) {
        hb_face_destroy(value);
    }

    LruCache<int32_t, hb_face_t*> mCache;
private:
    static const size_t kMaxEntries = 100;
};

176 177 178 179 180
static unsigned int disabledDecomposeCompatibility(hb_unicode_funcs_t*, hb_codepoint_t,
                                                   hb_codepoint_t*, void*) {
    return 0;
}

181 182 183
class LayoutEngine : public Singleton<LayoutEngine> {
public:
    LayoutEngine() {
184 185 186 187
        unicodeFunctions = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
        /* Disable the function used for compatibility decomposition */
        hb_unicode_funcs_set_decompose_compatibility_func(
                unicodeFunctions, disabledDecomposeCompatibility, NULL, NULL);
188
        hbBuffer = hb_buffer_create();
189
        hb_buffer_set_unicode_funcs(hbBuffer, unicodeFunctions);
190 191 192
    }

    hb_buffer_t* hbBuffer;
193
    hb_unicode_funcs_t* unicodeFunctions;
194 195 196 197 198 199 200
    LayoutCache layoutCache;
    HbFaceCache hbFaceCache;
};

ANDROID_SINGLETON_STATIC_INSTANCE(LayoutEngine);

bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const {
R
Raph Levien 已提交
201 202 203 204 205 206 207
    return mId == other.mId
            && mStart == other.mStart
            && mCount == other.mCount
            && mStyle == other.mStyle
            && mSize == other.mSize
            && mScaleX == other.mScaleX
            && mSkewX == other.mSkewX
B
Behdad Esfahbod 已提交
208
            && mLetterSpacing == other.mLetterSpacing
R
Raph Levien 已提交
209 210
            && mPaintFlags == other.mPaintFlags
            && mIsRtl == other.mIsRtl
B
Behdad Esfahbod 已提交
211 212
            && mNchars == other.mNchars
            && !memcmp(mChars, other.mChars, mNchars * sizeof(uint16_t));
213 214 215 216 217 218 219 220
}

hash_t LayoutCacheKey::hash() const {
    uint32_t hash = JenkinsHashMix(0, mId);
    hash = JenkinsHashMix(hash, mStart);
    hash = JenkinsHashMix(hash, mCount);
    hash = JenkinsHashMix(hash, hash_type(mStyle));
    hash = JenkinsHashMix(hash, hash_type(mSize));
R
Raph Levien 已提交
221 222
    hash = JenkinsHashMix(hash, hash_type(mScaleX));
    hash = JenkinsHashMix(hash, hash_type(mSkewX));
B
Behdad Esfahbod 已提交
223
    hash = JenkinsHashMix(hash, hash_type(mLetterSpacing));
R
Raph Levien 已提交
224
    hash = JenkinsHashMix(hash, hash_type(mPaintFlags));
225
    hash = JenkinsHashMix(hash, hash_type(mIsRtl));
B
Behdad Esfahbod 已提交
226
    hash = JenkinsHashMixShorts(hash, mChars, mNchars);
227 228 229 230 231 232 233
    return JenkinsHashWhiten(hash);
}

hash_t hash_type(const LayoutCacheKey& key) {
    return key.hash();
}

R
Raph Levien 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
Bitmap::Bitmap(int width, int height) : width(width), height(height) {
    buf = new uint8_t[width * height]();
}

Bitmap::~Bitmap() {
    delete[] buf;
}

void Bitmap::writePnm(std::ofstream &o) const {
    o << "P5" << std::endl;
    o << width << " " << height << std::endl;
    o << "255" << std::endl;
    o.write((const char *)buf, width * height);
    o.close();
}

R
Raph Levien 已提交
250
void Bitmap::drawGlyph(const GlyphBitmap& bitmap, int x, int y) {
R
Raph Levien 已提交
251
    int bmw = bitmap.width;
R
Raph Levien 已提交
252 253 254
    int bmh = bitmap.height;
    x += bitmap.left;
    y -= bitmap.top;
R
Raph Levien 已提交
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    int x0 = std::max(0, x);
    int x1 = std::min(width, x + bmw);
    int y0 = std::max(0, y);
    int y1 = std::min(height, y + bmh);
    const unsigned char* src = bitmap.buffer + (y0 - y) * bmw + (x0 - x);
    uint8_t* dst = buf + y0 * width;
    for (int yy = y0; yy < y1; yy++) {
        for (int xx = x0; xx < x1; xx++) {
            int pixel = (int)dst[xx] + (int)src[xx - x];
            pixel = pixel > 0xff ? 0xff : pixel;
            dst[xx] = pixel;
        }
        src += bmw;
        dst += width;
    }
}

272 273 274 275 276 277 278 279 280 281 282
void MinikinRect::join(const MinikinRect& r) {
    if (isEmpty()) {
        set(r);
    } else if (!r.isEmpty()) {
        mLeft = std::min(mLeft, r.mLeft);
        mTop = std::min(mTop, r.mTop);
        mRight = std::max(mRight, r.mRight);
        mBottom = std::max(mBottom, r.mBottom);
    }
}

283
// Deprecated. Remove when callers are removed.
R
Raph Levien 已提交
284 285 286
void Layout::init() {
}

287 288 289 290 291 292 293 294
void Layout::reset() {
    mGlyphs.clear();
    mFaces.clear();
    mBounds.setEmpty();
    mAdvances.clear();
    mAdvance = 0;
}

295
void Layout::setFontCollection(const FontCollection* collection) {
R
Raph Levien 已提交
296 297 298 299
    mCollection = collection;
}

hb_blob_t* referenceTable(hb_face_t* face, hb_tag_t tag, void* userData)  {
300
    MinikinFont* font = reinterpret_cast<MinikinFont*>(userData);
R
Raph Levien 已提交
301 302 303
    size_t length = 0;
    bool ok = font->GetTable(tag, NULL, &length);
    if (!ok) {
R
Raph Levien 已提交
304 305
        return 0;
    }
306
    char* buffer = reinterpret_cast<char*>(malloc(length));
R
Raph Levien 已提交
307 308 309
    if (!buffer) {
        return 0;
    }
R
Raph Levien 已提交
310 311 312 313
    ok = font->GetTable(tag, reinterpret_cast<uint8_t*>(buffer), &length);
    printf("referenceTable %c%c%c%c length=%d %d\n",
        (tag >>24) & 0xff, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff, length, ok);
    if (!ok) {
R
Raph Levien 已提交
314 315 316 317 318 319 320 321 322
        free(buffer);
        return 0;
    }
    return hb_blob_create(const_cast<char*>(buffer), length,
        HB_MEMORY_MODE_WRITABLE, buffer, free);
}

static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData)
{
323
    MinikinPaint* paint = reinterpret_cast<MinikinPaint*>(fontData);
R
Raph Levien 已提交
324 325 326 327 328 329 330
    MinikinFont* font = paint->font;
    uint32_t glyph_id;
    bool ok = font->GetGlyph(unicode, &glyph_id);
    if (ok) {
        *glyph = glyph_id;
    }
    return ok;
R
Raph Levien 已提交
331 332 333 334
}

static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData)
{
335
    MinikinPaint* paint = reinterpret_cast<MinikinPaint*>(fontData);
R
Raph Levien 已提交
336 337 338
    MinikinFont* font = paint->font;
    float advance = font->GetHorizontalAdvance(glyph, *paint);
    return 256 * advance + 0.5;
R
Raph Levien 已提交
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
}

static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* userData)
{
    // Just return true, following the way that Harfbuzz-FreeType
    // implementation does.
    return true;
}

hb_font_funcs_t* getHbFontFuncs() {
    static hb_font_funcs_t* hbFontFuncs = 0;

    if (hbFontFuncs == 0) {
        hbFontFuncs = hb_font_funcs_create();
        hb_font_funcs_set_glyph_func(hbFontFuncs, harfbuzzGetGlyph, 0, 0);
        hb_font_funcs_set_glyph_h_advance_func(hbFontFuncs, harfbuzzGetGlyphHorizontalAdvance, 0, 0);
        hb_font_funcs_set_glyph_h_origin_func(hbFontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0);
        hb_font_funcs_make_immutable(hbFontFuncs);
    }
    return hbFontFuncs;
}

361 362 363 364 365 366 367 368 369 370 371 372 373
static hb_face_t* getHbFace(MinikinFont* minikinFont) {
    HbFaceCache& cache = LayoutEngine::getInstance().hbFaceCache;
    int32_t fontId = minikinFont->GetUniqueId();
    hb_face_t* face = cache.mCache.get(fontId);
    if (face == NULL) {
        face = hb_face_create_for_tables(referenceTable, minikinFont, NULL);
        cache.mCache.put(fontId, face);
    }
    return face;
}

static hb_font_t* create_hb_font(MinikinFont* minikinFont, MinikinPaint* minikinPaint) {
    hb_face_t* face = getHbFace(minikinFont);
R
Raph Levien 已提交
374
    hb_font_t* font = hb_font_create(face);
R
Raph Levien 已提交
375
    hb_font_set_funcs(font, getHbFontFuncs(), minikinPaint, 0);
R
Raph Levien 已提交
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
    return font;
}

static float HBFixedToFloat(hb_position_t v)
{
    return scalbnf (v, -8);
}

static hb_position_t HBFloatToFixed(float v)
{
    return scalbnf (v, +8);
}

void Layout::dump() const {
    for (size_t i = 0; i < mGlyphs.size(); i++) {
        const LayoutGlyph& glyph = mGlyphs[i];
        std::cout << glyph.glyph_id << ": " << glyph.x << ", " << glyph.y << std::endl;
    }
}

R
Raph Levien 已提交
396
int Layout::findFace(FakedFont face, LayoutContext* ctx) {
R
Raph Levien 已提交
397 398
    unsigned int ix;
    for (ix = 0; ix < mFaces.size(); ix++) {
R
Raph Levien 已提交
399
        if (mFaces[ix].font == face.font) {
R
Raph Levien 已提交
400 401 402 403
            return ix;
        }
    }
    mFaces.push_back(face);
404 405 406
    // Note: ctx == NULL means we're copying from the cache, no need to create
    // corresponding hb_font object.
    if (ctx != NULL) {
R
Raph Levien 已提交
407
        hb_font_t* font = create_hb_font(face.font, &ctx->paint);
408 409
        ctx->hbFonts.push_back(font);
    }
R
Raph Levien 已提交
410 411 412
    return ix;
}

413
static hb_script_t codePointToScript(hb_codepoint_t codepoint) {
414
    static hb_unicode_funcs_t* u = 0;
415
    if (!u) {
416
        u = LayoutEngine::getInstance().unicodeFunctions;
417 418 419 420
    }
    return hb_unicode_script(u, codepoint);
}

421
static hb_codepoint_t decodeUtf16(const uint16_t* chars, size_t len, ssize_t* iter) {
422 423 424 425 426 427 428 429 430 431 432 433
    const uint16_t v = chars[(*iter)++];
    // test whether v in (0xd800..0xdfff), lead or trail surrogate
    if ((v & 0xf800) == 0xd800) {
        // test whether v in (0xd800..0xdbff), lead surrogate
        if (size_t(*iter) < len && (v & 0xfc00) == 0xd800) {
            const uint16_t v2 = chars[(*iter)++];
            // test whether v2 in (0xdc00..0xdfff), trail surrogate
            if ((v2 & 0xfc00) == 0xdc00) {
                // (0xd800 0xdc00) in utf-16 maps to 0x10000 in ucs-32
                const hb_codepoint_t delta = (0xd800 << 10) + 0xdc00 - 0x10000;
                return (((hb_codepoint_t)v) << 10) + v2 - delta;
            }
434 435
            (*iter) -= 1;
            return 0xFFFDu;
436
        } else {
437
            return 0xFFFDu;
438 439 440 441 442 443
        }
    } else {
        return v;
    }
}

444
static hb_script_t getScriptRun(const uint16_t* chars, size_t len, ssize_t* iter) {
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
    if (size_t(*iter) == len) {
        return HB_SCRIPT_UNKNOWN;
    }
    uint32_t cp = decodeUtf16(chars, len, iter);
    hb_script_t current_script = codePointToScript(cp);
    for (;;) {
        if (size_t(*iter) == len)
            break;
        const ssize_t prev_iter = *iter;
        cp = decodeUtf16(chars, len, iter);
        const hb_script_t script = codePointToScript(cp);
        if (script != current_script) {
            if (current_script == HB_SCRIPT_INHERITED ||
                current_script == HB_SCRIPT_COMMON) {
                current_script = script;
            } else if (script == HB_SCRIPT_INHERITED ||
                script == HB_SCRIPT_COMMON) {
                continue;
            } else {
                *iter = prev_iter;
                break;
            }
        }
    }
    if (current_script == HB_SCRIPT_INHERITED) {
        current_script = HB_SCRIPT_COMMON;
    }

    return current_script;
}

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
/**
 * For the purpose of layout, a word break is a boundary with no
 * kerning or complex script processing. This is necessarily a
 * heuristic, but should be accurate most of the time.
 */
static bool isWordBreak(int c) {
    if (c == ' ' || (c >= 0x2000 && c <= 0x200a) || c == 0x3000) {
        // spaces
        return true;
    }
    if ((c >= 0x3400 && c <= 0x9fff)) {
        // CJK ideographs (and yijing hexagram symbols)
        return true;
    }
    // Note: kana is not included, as sophisticated fonts may kern kana
    return false;
}

/**
 * Return offset of previous word break. It is either < offset or == 0.
 */
static size_t getPrevWordBreak(const uint16_t* chars, size_t offset) {
    if (offset == 0) return 0;
    if (isWordBreak(chars[offset - 1])) {
        return offset - 1;
    }
    for (size_t i = offset - 1; i > 0; i--) {
        if (isWordBreak(chars[i - 1])) {
            return i;
        }
    }
    return 0;
}

/**
 * Return offset of next word break. It is either > offset or == len.
 */
static size_t getNextWordBreak(const uint16_t* chars, size_t offset, size_t len) {
    if (offset >= len) return len;
    if (isWordBreak(chars[offset])) {
        return offset + 1;
    }
    for (size_t i = offset + 1; i < len; i++) {
        if (isWordBreak(chars[i])) {
            return i;
        }
    }
    return len;
}

526 527 528 529 530 531 532 533
void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
        int bidiFlags, const FontStyle &style, const MinikinPaint &paint) {
    AutoMutex _l(gMinikinLock);

    LayoutContext ctx;
    ctx.style = style;
    ctx.paint = paint;

R
Raph Levien 已提交
534 535
    bool isRtl = (bidiFlags & kDirection_Mask) != 0;
    bool doSingleRun = true;
R
Raph Levien 已提交
536

537
    reset();
538
    mAdvances.resize(count, 0);
539

R
Raph Levien 已提交
540 541 542 543 544 545 546 547 548 549
    if (!(bidiFlags == kBidi_Force_LTR || bidiFlags == kBidi_Force_RTL)) {
        UBiDi* bidi = ubidi_open();
        if (bidi) {
            UErrorCode status = U_ZERO_ERROR;
            UBiDiLevel bidiReq = bidiFlags;
            if (bidiFlags == kBidi_Default_LTR) {
                bidiReq = UBIDI_DEFAULT_LTR;
            } else if (bidiFlags == kBidi_Default_RTL) {
                bidiReq = UBIDI_DEFAULT_RTL;
            }
550
            ubidi_setPara(bidi, buf, bufSize, bidiReq, NULL, &status);
R
Raph Levien 已提交
551 552 553
            if (U_SUCCESS(status)) {
                int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask;
                ssize_t rc = ubidi_countRuns(bidi, &status);
554 555
                if (!U_SUCCESS(status) || rc < 0) {
                    ALOGW("error counting bidi runs, status = %d", status);
R
Raph Levien 已提交
556 557 558 559 560 561 562 563 564 565 566 567
                }
                if (!U_SUCCESS(status) || rc <= 1) {
                    isRtl = (paraDir == kBidi_RTL);
                } else {
                    doSingleRun = false;
                    // iterate through runs
                    for (ssize_t i = 0; i < (ssize_t)rc; i++) {
                        int32_t startRun = -1;
                        int32_t lengthRun = -1;
                        UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
                        if (startRun == -1 || lengthRun == -1) {
                            ALOGE("invalid visual run");
568 569
                            // skip the invalid run
                            continue;
R
Raph Levien 已提交
570
                        }
R
Raph Levien 已提交
571 572 573 574 575 576 577 578
                        int32_t endRun = std::min(startRun + lengthRun, int32_t(start + count));
                        startRun = std::max(startRun, int32_t(start));
                        lengthRun = endRun - startRun;
                        if (lengthRun > 0) {
                            isRtl = (runDir == UBIDI_RTL);
                            doLayoutRunCached(buf, startRun, lengthRun, bufSize, isRtl, &ctx,
                                start);
                        }
R
Raph Levien 已提交
579 580 581 582 583 584 585 586 587 588 589
                    }
                }
            } else {
                ALOGE("error calling ubidi_setPara, status = %d", status);
            }
            ubidi_close(bidi);
        } else {
            ALOGE("error creating bidi object");
        }
    }
    if (doSingleRun) {
R
Raph Levien 已提交
590
        doLayoutRunCached(buf, start, count, bufSize, isRtl, &ctx, start);
591
    }
B
Behdad Esfahbod 已提交
592
    ctx.clearHbFonts();
593 594 595
}

void Layout::doLayoutRunCached(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
R
Raph Levien 已提交
596
        bool isRtl, LayoutContext* ctx, size_t dstStart) {
597 598 599 600 601 602
    if (!isRtl) {
        // left to right
        size_t wordstart = start == bufSize ? start : getPrevWordBreak(buf, start + 1);
        size_t wordend;
        for (size_t iter = start; iter < start + count; iter = wordend) {
            wordend = getNextWordBreak(buf, iter, bufSize);
R
Raph Levien 已提交
603
            size_t wordcount = std::min(start + count, wordend) - iter;
604
            doLayoutWord(buf + wordstart, iter - wordstart, wordcount, wordend - wordstart,
R
Raph Levien 已提交
605
                    isRtl, ctx, iter - dstStart);
606 607 608 609 610 611 612 613 614
            wordstart = wordend;
        }
    } else {
        // right to left
        size_t wordstart;
        size_t end = start + count;
        size_t wordend = end == 0 ? 0 : getNextWordBreak(buf, end - 1, bufSize);
        for (size_t iter = end; iter > start; iter = wordstart) {
            wordstart = getPrevWordBreak(buf, iter);
R
Raph Levien 已提交
615
            size_t bufStart = std::max(start, wordstart);
616
            doLayoutWord(buf + wordstart, bufStart - wordstart, iter - bufStart,
R
Raph Levien 已提交
617
                    wordend - wordstart, isRtl, ctx, bufStart - dstStart);
618 619
            wordend = wordstart;
        }
R
Raph Levien 已提交
620 621 622
    }
}

623 624 625 626
void Layout::doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
        bool isRtl, LayoutContext* ctx, size_t bufStart) {
    LayoutCache& cache = LayoutEngine::getInstance().layoutCache;
    LayoutCacheKey key(mCollection, ctx->paint, ctx->style, buf, start, count, bufSize, isRtl);
B
Behdad Esfahbod 已提交
627
    bool skipCache = ctx->paint.skipCache();
B
Behdad Esfahbod 已提交
628 629 630 631 632 633 634
    if (skipCache) {
        Layout layout;
        key.doLayout(&layout, ctx, mCollection);
        appendLayout(&layout, bufStart);
    } else {
        Layout* layout = cache.get(key, ctx, mCollection);
        appendLayout(layout, bufStart);
635 636 637
    }
}

B
Behdad Esfahbod 已提交
638 639 640
static void addFeatures(const string &str, vector<hb_feature_t>* features) {
    if (!str.size())
        return;
R
Raph Levien 已提交
641

B
Behdad Esfahbod 已提交
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
    const char* start = str.c_str();
    const char* end = start + str.size();

    while (start < end) {
        static hb_feature_t feature;
        const char* p = strchr(start, ',');
        if (!p)
            p = end;
        /* We do not allow setting features on ranges.  As such, reject any
         * setting that has non-universal range. */
        if (hb_feature_from_string (start, p - start, &feature)
                && feature.start == 0 && feature.end == (unsigned int) -1)
            features->push_back(feature);
        start = p + 1;
    }
657 658
}

R
Raph Levien 已提交
659
void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
660 661
        bool isRtl, LayoutContext* ctx) {
    hb_buffer_t* buffer = LayoutEngine::getInstance().hbBuffer;
R
Raph Levien 已提交
662
    vector<FontCollection::Run> items;
663
    mCollection->itemize(buf + start, count, ctx->style, &items);
R
Raph Levien 已提交
664 665 666 667
    if (isRtl) {
        std::reverse(items.begin(), items.end());
    }

668
    vector<hb_feature_t> features;
B
Behdad Esfahbod 已提交
669 670 671 672 673 674 675 676 677 678 679 680
    // Disable default-on non-required ligature features if letter-spacing
    // See http://dev.w3.org/csswg/css-text-3/#letter-spacing-property
    // "When the effective spacing between two characters is not zero (due to
    // either justification or a non-zero value of letter-spacing), user agents
    // should not apply optional ligatures."
    if (fabs(ctx->paint.letterSpacing) > 0.03)
    {
        static const hb_feature_t no_liga = { HB_TAG('l', 'i', 'g', 'a'), 0, 0, ~0u };
        static const hb_feature_t no_clig = { HB_TAG('c', 'l', 'i', 'g'), 0, 0, ~0u };
        features.push_back(no_liga);
        features.push_back(no_clig);
    }
B
Behdad Esfahbod 已提交
681
    addFeatures(ctx->paint.fontFeatureSettings, &features);
682

B
Behdad Esfahbod 已提交
683 684 685
    double size = ctx->paint.size;
    double scaleX = ctx->paint.scaleX;
    double letterSpace = ctx->paint.letterSpacing * size * scaleX;
R
Raph Levien 已提交
686 687 688 689 690 691 692 693
    double letterSpaceHalfLeft;
    if ((ctx->paint.paintFlags & LinearTextFlag) == 0) {
        letterSpace = round(letterSpace);
        letterSpaceHalfLeft = floor(letterSpace * 0.5);
    } else {
        letterSpaceHalfLeft = letterSpace * 0.5;
    }
    double letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft;
B
Behdad Esfahbod 已提交
694

R
Raph Levien 已提交
695
    float x = mAdvance;
R
Raph Levien 已提交
696 697 698
    float y = 0;
    for (size_t run_ix = 0; run_ix < items.size(); run_ix++) {
        FontCollection::Run &run = items[run_ix];
R
Raph Levien 已提交
699
        if (run.fakedFont.font == NULL) {
700 701 702
            ALOGE("no font for run starting u+%04x length %d", buf[run.start], run.end - run.start);
            continue;
        }
R
Raph Levien 已提交
703 704 705
        int font_ix = findFace(run.fakedFont, ctx);
        ctx->paint.font = mFaces[font_ix].font;
        ctx->paint.fakery = mFaces[font_ix].fakery;
706
        hb_font_t* hbFont = ctx->hbFonts[font_ix];
R
Raph Levien 已提交
707 708 709 710
#ifdef VERBOSE
        std::cout << "Run " << run_ix << ", font " << font_ix <<
            " [" << run.start << ":" << run.end << "]" << std::endl;
#endif
B
Behdad Esfahbod 已提交
711

R
Raph Levien 已提交
712 713
        hb_font_set_ppem(hbFont, size * scaleX, size);
        hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size));
R
Raph Levien 已提交
714

R
Raph Levien 已提交
715 716 717
        // TODO: if there are multiple scripts within a font in an RTL run,
        // we need to reorder those runs. This is unlikely with our current
        // font stack, but should be done for correctness.
R
Raph Levien 已提交
718 719
        ssize_t srunend;
        for (ssize_t srunstart = run.start; srunstart < run.end; srunstart = srunend) {
720
            srunend = srunstart;
R
Raph Levien 已提交
721
            hb_script_t script = getScriptRun(buf + start, run.end, &srunend);
722

723
            hb_buffer_clear_contents(buffer);
724
            hb_buffer_set_script(buffer, script);
R
Raph Levien 已提交
725
            hb_buffer_set_direction(buffer, isRtl? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
B
Behdad Esfahbod 已提交
726 727 728
            FontLanguage language = ctx->style.getLanguage();
            if (language) {
                string lang = language.getString();
R
Raph Levien 已提交
729 730
                hb_buffer_set_language(buffer, hb_language_from_string(lang.c_str(), -1));
            }
R
Raph Levien 已提交
731
            hb_buffer_add_utf16(buffer, buf, bufSize, srunstart + start, srunend - srunstart);
732
            hb_shape(hbFont, buffer, features.empty() ? NULL : &features[0], features.size());
733
            unsigned int numGlyphs;
734 735
            hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs);
            hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer, NULL);
B
Behdad Esfahbod 已提交
736 737
            if (numGlyphs)
            {
R
Raph Levien 已提交
738 739
                mAdvances[info[0].cluster - start] += letterSpaceHalfLeft;
                x += letterSpaceHalfLeft;
B
Behdad Esfahbod 已提交
740
            }
741 742 743 744 745
            for (unsigned int i = 0; i < numGlyphs; i++) {
    #ifdef VERBOSE
                std::cout << positions[i].x_advance << " " << positions[i].y_advance << " " << positions[i].x_offset << " " << positions[i].y_offset << std::endl;            std::cout << "DoLayout " << info[i].codepoint <<
                ": " << HBFixedToFloat(positions[i].x_advance) << "; " << positions[i].x_offset << ", " << positions[i].y_offset << std::endl;
    #endif
B
Behdad Esfahbod 已提交
746
                if (i > 0 && info[i - 1].cluster != info[i].cluster) {
R
Raph Levien 已提交
747 748 749
                    mAdvances[info[i - 1].cluster - start] += letterSpaceHalfRight;
                    mAdvances[info[i].cluster - start] += letterSpaceHalfLeft;
                    x += letterSpace;
B
Behdad Esfahbod 已提交
750 751
                }

752 753
                hb_codepoint_t glyph_ix = info[i].codepoint;
                float xoff = HBFixedToFloat(positions[i].x_offset);
R
Raph Levien 已提交
754 755
                float yoff = -HBFixedToFloat(positions[i].y_offset);
                xoff += yoff * ctx->paint.skewX;
756 757 758
                LayoutGlyph glyph = {font_ix, glyph_ix, x + xoff, y + yoff};
                mGlyphs.push_back(glyph);
                float xAdvance = HBFixedToFloat(positions[i].x_advance);
R
Raph Levien 已提交
759 760 761
                if ((ctx->paint.paintFlags & LinearTextFlag) == 0) {
                    xAdvance = roundf(xAdvance);
                }
762
                MinikinRect glyphBounds;
763
                ctx->paint.font->GetBounds(&glyphBounds, glyph_ix, ctx->paint);
764 765
                glyphBounds.offset(x + xoff, y + yoff);
                mBounds.join(glyphBounds);
B
Behdad Esfahbod 已提交
766
                mAdvances[info[i].cluster - start] += xAdvance;
767 768
                x += xAdvance;
            }
B
Behdad Esfahbod 已提交
769 770
            if (numGlyphs)
            {
R
Raph Levien 已提交
771 772
                mAdvances[info[numGlyphs - 1].cluster - start] += letterSpaceHalfRight;
                x += letterSpaceHalfRight;
B
Behdad Esfahbod 已提交
773
            }
R
Raph Levien 已提交
774 775
        }
    }
R
Raph Levien 已提交
776
    mAdvance = x;
R
Raph Levien 已提交
777 778
}

779
void Layout::appendLayout(Layout* src, size_t start) {
B
Behdad Esfahbod 已提交
780 781 782 783 784 785 786
    int fontMapStack[16];
    int* fontMap;
    if (src->mFaces.size() < sizeof(fontMapStack) / sizeof(fontMapStack[0])) {
        fontMap = fontMapStack;
    } else {
        fontMap = new int[src->mFaces.size()];
    }
787 788
    for (size_t i = 0; i < src->mFaces.size(); i++) {
        int font_ix = findFace(src->mFaces[i], NULL);
B
Behdad Esfahbod 已提交
789
        fontMap[i] = font_ix;
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
    }
    int x0 = mAdvance;
    for (size_t i = 0; i < src->mGlyphs.size(); i++) {
        LayoutGlyph& srcGlyph = src->mGlyphs[i];
        int font_ix = fontMap[srcGlyph.font_ix];
        unsigned int glyph_id = srcGlyph.glyph_id;
        float x = x0 + srcGlyph.x;
        float y = srcGlyph.y;
        LayoutGlyph glyph = {font_ix, glyph_id, x, y};
        mGlyphs.push_back(glyph);
    }
    for (size_t i = 0; i < src->mAdvances.size(); i++) {
        mAdvances[i + start] = src->mAdvances[i];
    }
    MinikinRect srcBounds(src->mBounds);
    srcBounds.offset(x0, 0);
    mBounds.join(srcBounds);
    mAdvance += src->mAdvance;
B
Behdad Esfahbod 已提交
808 809 810 811

    if (fontMap != fontMapStack) {
        delete[] fontMap;
    }
812 813 814
}

void Layout::draw(Bitmap* surface, int x0, int y0, float size) const {
R
Raph Levien 已提交
815 816
    /*
    TODO: redo as MinikinPaint settings
R
Raph Levien 已提交
817 818 819 820 821
    if (mProps.hasTag(minikinHinting)) {
        int hintflags = mProps.value(minikinHinting).getIntValue();
        if (hintflags & 1) load_flags |= FT_LOAD_NO_HINTING;
        if (hintflags & 2) load_flags |= FT_LOAD_NO_AUTOHINT;
    }
R
Raph Levien 已提交
822
    */
R
Raph Levien 已提交
823 824
    for (size_t i = 0; i < mGlyphs.size(); i++) {
        const LayoutGlyph& glyph = mGlyphs[i];
R
Raph Levien 已提交
825
        MinikinFont* mf = mFaces[glyph.font_ix].font;
826
        MinikinFontFreeType* face = static_cast<MinikinFontFreeType*>(mf);
R
Raph Levien 已提交
827 828
        GlyphBitmap glyphBitmap;
        MinikinPaint paint;
829
        paint.size = size;
R
Raph Levien 已提交
830 831 832 833 834 835 836
        bool ok = face->Render(glyph.glyph_id, paint, &glyphBitmap);
        printf("glyphBitmap.width=%d, glyphBitmap.height=%d (%d, %d) x=%f, y=%f, ok=%d\n",
            glyphBitmap.width, glyphBitmap.height, glyphBitmap.left, glyphBitmap.top, glyph.x, glyph.y, ok);
        if (ok) {
            surface->drawGlyph(glyphBitmap,
                x0 + int(floor(glyph.x + 0.5)), y0 + int(floor(glyph.y + 0.5)));
        }
R
Raph Levien 已提交
837 838 839
    }
}

840 841 842 843
size_t Layout::nGlyphs() const {
    return mGlyphs.size();
}

844
MinikinFont* Layout::getFont(int i) const {
845
    const LayoutGlyph& glyph = mGlyphs[i];
R
Raph Levien 已提交
846 847 848 849 850 851
    return mFaces[glyph.font_ix].font;
}

FontFakery Layout::getFakery(int i) const {
    const LayoutGlyph& glyph = mGlyphs[i];
    return mFaces[glyph.font_ix].fakery;
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
}

unsigned int Layout::getGlyphId(int i) const {
    const LayoutGlyph& glyph = mGlyphs[i];
    return glyph.glyph_id;
}

float Layout::getX(int i) const {
    const LayoutGlyph& glyph = mGlyphs[i];
    return glyph.x;
}

float Layout::getY(int i) const {
    const LayoutGlyph& glyph = mGlyphs[i];
    return glyph.y;
}

R
Raph Levien 已提交
869 870 871 872
float Layout::getAdvance() const {
    return mAdvance;
}

873 874 875 876 877 878 879 880
void Layout::getAdvances(float* advances) {
    memcpy(advances, &mAdvances[0], mAdvances.size() * sizeof(float));
}

void Layout::getBounds(MinikinRect* bounds) {
    bounds->set(mBounds);
}

R
Raph Levien 已提交
881 882 883
void Layout::purgeCaches() {
    AutoMutex _l(gMinikinLock);
    LayoutCache& layoutCache = LayoutEngine::getInstance().layoutCache;
B
Behdad Esfahbod 已提交
884
    layoutCache.clear();
R
Raph Levien 已提交
885 886 887 888
    HbFaceCache& hbCache = LayoutEngine::getInstance().hbFaceCache;
    hbCache.mCache.clear();
}

R
Raph Levien 已提交
889
}  // namespace android