Layout.cpp 30.4 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
const int kDirection_Mask = 0x1;

B
Behdad Esfahbod 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60
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();
    }
};

61 62 63 64 65 66
// 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)
67 68
            : mChars(chars), mNchars(nchars),
            mStart(start), mCount(count), mId(collection->getId()), mStyle(style),
R
Raph Levien 已提交
69
            mSize(paint.size), mScaleX(paint.scaleX), mSkewX(paint.skewX),
B
Behdad Esfahbod 已提交
70
            mLetterSpacing(paint.letterSpacing),
71
            mPaintFlags(paint.paintFlags), mIsRtl(dir) {
72 73 74 75
    }
    bool operator==(const LayoutCacheKey &other) const;
    hash_t hash() const;

B
Behdad Esfahbod 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    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);
    }

93
private:
B
Behdad Esfahbod 已提交
94 95
    const uint16_t* mChars;
    size_t mNchars;
96 97 98 99 100
    size_t mStart;
    size_t mCount;
    uint32_t mId;  // for the font collection
    FontStyle mStyle;
    float mSize;
R
Raph Levien 已提交
101 102
    float mScaleX;
    float mSkewX;
B
Behdad Esfahbod 已提交
103
    float mLetterSpacing;
R
Raph Levien 已提交
104
    int32_t mPaintFlags;
105 106 107 108 109 110 111 112 113 114 115
    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 已提交
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
    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:
132 133
    // callback for OnEntryRemoved
    void operator()(LayoutCacheKey& key, Layout*& value) {
B
Behdad Esfahbod 已提交
134
        key.freeText();
135 136 137 138
        delete value;
    }

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

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    //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;
};

163 164 165 166 167
static unsigned int disabledDecomposeCompatibility(hb_unicode_funcs_t*, hb_codepoint_t,
                                                   hb_codepoint_t*, void*) {
    return 0;
}

168 169 170
class LayoutEngine : public Singleton<LayoutEngine> {
public:
    LayoutEngine() {
171 172 173 174
        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);
175
        hbBuffer = hb_buffer_create();
176
        hb_buffer_set_unicode_funcs(hbBuffer, unicodeFunctions);
177 178 179
    }

    hb_buffer_t* hbBuffer;
180
    hb_unicode_funcs_t* unicodeFunctions;
181 182 183 184 185 186 187
    LayoutCache layoutCache;
    HbFaceCache hbFaceCache;
};

ANDROID_SINGLETON_STATIC_INSTANCE(LayoutEngine);

bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const {
R
Raph Levien 已提交
188 189 190 191 192 193 194
    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 已提交
195
            && mLetterSpacing == other.mLetterSpacing
R
Raph Levien 已提交
196 197
            && mPaintFlags == other.mPaintFlags
            && mIsRtl == other.mIsRtl
B
Behdad Esfahbod 已提交
198 199
            && mNchars == other.mNchars
            && !memcmp(mChars, other.mChars, mNchars * sizeof(uint16_t));
200 201 202 203 204 205 206 207
}

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 已提交
208 209
    hash = JenkinsHashMix(hash, hash_type(mScaleX));
    hash = JenkinsHashMix(hash, hash_type(mSkewX));
B
Behdad Esfahbod 已提交
210
    hash = JenkinsHashMix(hash, hash_type(mLetterSpacing));
R
Raph Levien 已提交
211
    hash = JenkinsHashMix(hash, hash_type(mPaintFlags));
212
    hash = JenkinsHashMix(hash, hash_type(mIsRtl));
B
Behdad Esfahbod 已提交
213
    hash = JenkinsHashMixShorts(hash, mChars, mNchars);
214 215 216 217 218 219 220
    return JenkinsHashWhiten(hash);
}

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

R
Raph Levien 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
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 已提交
237
void Bitmap::drawGlyph(const GlyphBitmap& bitmap, int x, int y) {
R
Raph Levien 已提交
238
    int bmw = bitmap.width;
R
Raph Levien 已提交
239 240 241
    int bmh = bitmap.height;
    x += bitmap.left;
    y -= bitmap.top;
R
Raph Levien 已提交
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
    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;
    }
}

259 260 261 262 263 264 265 266 267 268 269
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);
    }
}

270
// Deprecated. Remove when callers are removed.
R
Raph Levien 已提交
271 272 273
void Layout::init() {
}

274 275 276 277 278 279 280 281
void Layout::reset() {
    mGlyphs.clear();
    mFaces.clear();
    mBounds.setEmpty();
    mAdvances.clear();
    mAdvance = 0;
}

282
void Layout::setFontCollection(const FontCollection* collection) {
R
Raph Levien 已提交
283 284 285 286
    mCollection = collection;
}

hb_blob_t* referenceTable(hb_face_t* face, hb_tag_t tag, void* userData)  {
287
    MinikinFont* font = reinterpret_cast<MinikinFont*>(userData);
R
Raph Levien 已提交
288 289 290
    size_t length = 0;
    bool ok = font->GetTable(tag, NULL, &length);
    if (!ok) {
R
Raph Levien 已提交
291 292
        return 0;
    }
293
    char* buffer = reinterpret_cast<char*>(malloc(length));
R
Raph Levien 已提交
294 295 296
    if (!buffer) {
        return 0;
    }
R
Raph Levien 已提交
297 298 299 300
    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 已提交
301 302 303 304 305 306 307 308 309
        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)
{
310
    MinikinPaint* paint = reinterpret_cast<MinikinPaint*>(fontData);
R
Raph Levien 已提交
311 312 313 314 315 316 317
    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 已提交
318 319 320 321
}

static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData)
{
322
    MinikinPaint* paint = reinterpret_cast<MinikinPaint*>(fontData);
R
Raph Levien 已提交
323 324 325
    MinikinFont* font = paint->font;
    float advance = font->GetHorizontalAdvance(glyph, *paint);
    return 256 * advance + 0.5;
R
Raph Levien 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
}

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;
}

348 349 350 351 352 353 354 355 356 357 358 359 360
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 已提交
361
    hb_font_t* font = hb_font_create(face);
R
Raph Levien 已提交
362
    hb_font_set_funcs(font, getHbFontFuncs(), minikinPaint, 0);
R
Raph Levien 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    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 已提交
383
int Layout::findFace(FakedFont face, LayoutContext* ctx) {
R
Raph Levien 已提交
384 385
    unsigned int ix;
    for (ix = 0; ix < mFaces.size(); ix++) {
R
Raph Levien 已提交
386
        if (mFaces[ix].font == face.font) {
R
Raph Levien 已提交
387 388 389 390
            return ix;
        }
    }
    mFaces.push_back(face);
391 392 393
    // Note: ctx == NULL means we're copying from the cache, no need to create
    // corresponding hb_font object.
    if (ctx != NULL) {
R
Raph Levien 已提交
394
        hb_font_t* font = create_hb_font(face.font, &ctx->paint);
395 396
        ctx->hbFonts.push_back(font);
    }
R
Raph Levien 已提交
397 398 399
    return ix;
}

400
static hb_script_t codePointToScript(hb_codepoint_t codepoint) {
401
    static hb_unicode_funcs_t* u = 0;
402
    if (!u) {
403
        u = LayoutEngine::getInstance().unicodeFunctions;
404 405 406 407
    }
    return hb_unicode_script(u, codepoint);
}

408
static hb_codepoint_t decodeUtf16(const uint16_t* chars, size_t len, ssize_t* iter) {
409 410 411 412 413 414 415 416 417 418 419 420
    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;
            }
421 422
            (*iter) -= 1;
            return 0xFFFDu;
423
        } else {
424
            return 0xFFFDu;
425 426 427 428 429 430
        }
    } else {
        return v;
    }
}

431
static hb_script_t getScriptRun(const uint16_t* chars, size_t len, ssize_t* iter) {
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
    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;
}

463 464 465 466 467 468 469 470 471 472 473 474 475 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
/**
 * 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;
}

513 514 515 516 517 518 519 520
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 已提交
521 522
    bool isRtl = (bidiFlags & kDirection_Mask) != 0;
    bool doSingleRun = true;
R
Raph Levien 已提交
523

524
    reset();
525
    mAdvances.resize(count, 0);
526

R
Raph Levien 已提交
527 528 529 530 531 532 533 534 535 536
    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;
            }
537
            ubidi_setPara(bidi, buf, bufSize, bidiReq, NULL, &status);
R
Raph Levien 已提交
538 539 540
            if (U_SUCCESS(status)) {
                int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask;
                ssize_t rc = ubidi_countRuns(bidi, &status);
541 542
                if (!U_SUCCESS(status) || rc < 0) {
                    ALOGW("error counting bidi runs, status = %d", status);
R
Raph Levien 已提交
543 544 545 546 547 548 549 550 551 552 553 554
                }
                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");
555 556
                            // skip the invalid run
                            continue;
R
Raph Levien 已提交
557
                        }
R
Raph Levien 已提交
558 559 560 561 562 563 564 565
                        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 已提交
566 567 568 569 570 571 572 573 574 575 576
                    }
                }
            } else {
                ALOGE("error calling ubidi_setPara, status = %d", status);
            }
            ubidi_close(bidi);
        } else {
            ALOGE("error creating bidi object");
        }
    }
    if (doSingleRun) {
R
Raph Levien 已提交
577
        doLayoutRunCached(buf, start, count, bufSize, isRtl, &ctx, start);
578
    }
B
Behdad Esfahbod 已提交
579
    ctx.clearHbFonts();
580 581 582
}

void Layout::doLayoutRunCached(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
R
Raph Levien 已提交
583
        bool isRtl, LayoutContext* ctx, size_t dstStart) {
584
    HyphenEdit hyphen = ctx->paint.hyphenEdit;
585 586 587 588 589 590
    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);
591 592
            // Only apply hyphen to the last word in the string.
            ctx->paint.hyphenEdit = wordend >= start + count ? hyphen : HyphenEdit();
R
Raph Levien 已提交
593
            size_t wordcount = std::min(start + count, wordend) - iter;
594
            doLayoutWord(buf + wordstart, iter - wordstart, wordcount, wordend - wordstart,
R
Raph Levien 已提交
595
                    isRtl, ctx, iter - dstStart);
596 597 598 599 600 601 602 603 604
            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);
605 606
            // Only apply hyphen to the last (leftmost) word in the string.
            ctx->paint.hyphenEdit = iter == end ? hyphen : HyphenEdit();
R
Raph Levien 已提交
607
            size_t bufStart = std::max(start, wordstart);
608
            doLayoutWord(buf + wordstart, bufStart - wordstart, iter - bufStart,
R
Raph Levien 已提交
609
                    wordend - wordstart, isRtl, ctx, bufStart - dstStart);
610 611
            wordend = wordstart;
        }
R
Raph Levien 已提交
612 613 614
    }
}

615 616 617 618
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 已提交
619
    bool skipCache = ctx->paint.skipCache();
B
Behdad Esfahbod 已提交
620 621 622 623 624 625 626
    if (skipCache) {
        Layout layout;
        key.doLayout(&layout, ctx, mCollection);
        appendLayout(&layout, bufStart);
    } else {
        Layout* layout = cache.get(key, ctx, mCollection);
        appendLayout(layout, bufStart);
627 628 629
    }
}

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

B
Behdad Esfahbod 已提交
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
    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;
    }
649 650
}

R
Raph Levien 已提交
651
void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
652 653
        bool isRtl, LayoutContext* ctx) {
    hb_buffer_t* buffer = LayoutEngine::getInstance().hbBuffer;
R
Raph Levien 已提交
654
    vector<FontCollection::Run> items;
655
    mCollection->itemize(buf + start, count, ctx->style, &items);
R
Raph Levien 已提交
656 657 658 659
    if (isRtl) {
        std::reverse(items.begin(), items.end());
    }

660
    vector<hb_feature_t> features;
B
Behdad Esfahbod 已提交
661 662 663 664 665 666 667 668 669 670 671 672
    // 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 已提交
673
    addFeatures(ctx->paint.fontFeatureSettings, &features);
674

B
Behdad Esfahbod 已提交
675 676 677
    double size = ctx->paint.size;
    double scaleX = ctx->paint.scaleX;
    double letterSpace = ctx->paint.letterSpacing * size * scaleX;
R
Raph Levien 已提交
678 679 680 681 682 683 684 685
    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 已提交
686

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

R
Raph Levien 已提交
704 705
        hb_font_set_ppem(hbFont, size * scaleX, size);
        hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size));
R
Raph Levien 已提交
706

R
Raph Levien 已提交
707 708 709
        // 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 已提交
710 711
        ssize_t srunend;
        for (ssize_t srunstart = run.start; srunstart < run.end; srunstart = srunend) {
712
            srunend = srunstart;
R
Raph Levien 已提交
713
            hb_script_t script = getScriptRun(buf + start, run.end, &srunend);
714

715
            hb_buffer_clear_contents(buffer);
716
            hb_buffer_set_script(buffer, script);
R
Raph Levien 已提交
717
            hb_buffer_set_direction(buffer, isRtl? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
B
Behdad Esfahbod 已提交
718 719 720
            FontLanguage language = ctx->style.getLanguage();
            if (language) {
                string lang = language.getString();
R
Raph Levien 已提交
721 722
                hb_buffer_set_language(buffer, hb_language_from_string(lang.c_str(), -1));
            }
R
Raph Levien 已提交
723
            hb_buffer_add_utf16(buffer, buf, bufSize, srunstart + start, srunend - srunstart);
724 725 726 727 728 729
            if (ctx->paint.hyphenEdit.hasHyphen() && srunend > srunstart) {
                // TODO: check whether this is really the desired semantics. It could have the
                // effect of assigning the hyphen width to a nonspacing mark
                unsigned int lastCluster = srunend - 1;
                hb_buffer_add(buffer, 0x2010, lastCluster);
            }
730
            hb_shape(hbFont, buffer, features.empty() ? NULL : &features[0], features.size());
731
            unsigned int numGlyphs;
732 733
            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 已提交
734 735
            if (numGlyphs)
            {
R
Raph Levien 已提交
736 737
                mAdvances[info[0].cluster - start] += letterSpaceHalfLeft;
                x += letterSpaceHalfLeft;
B
Behdad Esfahbod 已提交
738
            }
739 740 741 742 743
            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 已提交
744
                if (i > 0 && info[i - 1].cluster != info[i].cluster) {
R
Raph Levien 已提交
745 746 747
                    mAdvances[info[i - 1].cluster - start] += letterSpaceHalfRight;
                    mAdvances[info[i].cluster - start] += letterSpaceHalfLeft;
                    x += letterSpace;
B
Behdad Esfahbod 已提交
748 749
                }

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

782
void Layout::appendLayout(Layout* src, size_t start) {
B
Behdad Esfahbod 已提交
783 784 785 786 787 788 789
    int fontMapStack[16];
    int* fontMap;
    if (src->mFaces.size() < sizeof(fontMapStack) / sizeof(fontMapStack[0])) {
        fontMap = fontMapStack;
    } else {
        fontMap = new int[src->mFaces.size()];
    }
790 791
    for (size_t i = 0; i < src->mFaces.size(); i++) {
        int font_ix = findFace(src->mFaces[i], NULL);
B
Behdad Esfahbod 已提交
792
        fontMap[i] = font_ix;
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
    }
    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 已提交
811 812 813 814

    if (fontMap != fontMapStack) {
        delete[] fontMap;
    }
815 816 817
}

void Layout::draw(Bitmap* surface, int x0, int y0, float size) const {
R
Raph Levien 已提交
818 819
    /*
    TODO: redo as MinikinPaint settings
R
Raph Levien 已提交
820 821 822 823 824
    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 已提交
825
    */
R
Raph Levien 已提交
826 827
    for (size_t i = 0; i < mGlyphs.size(); i++) {
        const LayoutGlyph& glyph = mGlyphs[i];
R
Raph Levien 已提交
828
        MinikinFont* mf = mFaces[glyph.font_ix].font;
829
        MinikinFontFreeType* face = static_cast<MinikinFontFreeType*>(mf);
R
Raph Levien 已提交
830 831
        GlyphBitmap glyphBitmap;
        MinikinPaint paint;
832
        paint.size = size;
R
Raph Levien 已提交
833 834 835 836 837 838 839
        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 已提交
840 841 842
    }
}

843 844 845 846
size_t Layout::nGlyphs() const {
    return mGlyphs.size();
}

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

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

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 已提交
872 873 874 875
float Layout::getAdvance() const {
    return mAdvance;
}

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

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

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

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