Seigo Nonaka 99ef32cef0 Do not keep FontCollection reference in Layout.
LayoutCache only keeps result of layout and can live after
FontCollection is destructed by GC.

This kind of failure will be captured by minikin_stress_tests in the
subsequent CL (I1bf4ba43e6e97cd04e7d6dd42d388dd17ce64c7b)

Test: ran minikin_tests
Bug: 36223724
Change-Id: I639b73c0f1041549158c43212a901c82df4b02db
2017-03-15 15:17:43 +00:00

162 lines
5.1 KiB
C++

/*
* 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.
*/
#ifndef MINIKIN_LAYOUT_H
#define MINIKIN_LAYOUT_H
#include <hb.h>
#include <memory>
#include <vector>
#include <minikin/FontCollection.h>
#include <minikin/MinikinFontFreeType.h>
namespace minikin {
// The Bitmap class is for debugging. We'll probably move it out
// of here into a separate lightweight software rendering module
// (optional, as we'd hope most clients would do their own)
class Bitmap {
public:
Bitmap(int width, int height);
~Bitmap();
void writePnm(std::ofstream& o) const;
void drawGlyph(const GlyphBitmap& bitmap, int x, int y);
private:
int width;
int height;
uint8_t* buf;
};
struct LayoutGlyph {
// index into mFaces and mHbFonts vectors. We could imagine
// moving this into a run length representation, because it's
// more efficient for long strings, and we'll probably need
// something like that for paint attributes (color, underline,
// fake b/i, etc), as having those per-glyph is bloated.
int font_ix;
unsigned int glyph_id;
float x;
float y;
};
// Internal state used during layout operation
struct LayoutContext;
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
};
// Lifecycle and threading assumptions for Layout:
// The object is assumed to be owned by a single thread; multiple threads
// may not mutate it at the same time.
class Layout {
public:
Layout() : mGlyphs(), mAdvances(), mFaces(), mAdvance(0), mBounds() {
mBounds.setEmpty();
}
Layout(Layout&& layout) = default;
// Forbid copying and assignment.
Layout(const Layout&) = delete;
void operator=(const Layout&) = delete;
void dump() const;
void doLayout(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
int bidiFlags, const FontStyle &style, const MinikinPaint &paint,
const std::shared_ptr<FontCollection>& collection);
static float measureText(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
int bidiFlags, const FontStyle &style, const MinikinPaint &paint,
const std::shared_ptr<FontCollection>& collection, float* advances);
void draw(minikin::Bitmap*, int x0, int y0, float size) const;
// public accessors
size_t nGlyphs() const;
const MinikinFont* getFont(int i) const;
FontFakery getFakery(int i) const;
unsigned int getGlyphId(int i) const;
float getX(int i) const;
float getY(int i) const;
float getAdvance() const;
// Get advances, copying into caller-provided buffer. The size of this
// buffer must match the length of the string (count arg to doLayout).
void getAdvances(float* advances);
// The i parameter is an offset within the buf relative to start, it is < count, where
// start and count are the parameters to doLayout
float getCharAdvance(size_t i) const { return mAdvances[i]; }
void getBounds(MinikinRect* rect) const;
// Purge all caches, useful in low memory conditions
static void purgeCaches();
private:
friend class LayoutCacheKey;
// Find a face in the mFaces vector, or create a new entry
int findFace(const FakedFont& face, LayoutContext* ctx);
// Clears layout, ready to be used again
void reset();
// Lay out a single bidi run
// When layout is not null, layout info will be stored in the object.
// When advances is not null, measurement results will be stored in the array.
static float doLayoutRunCached(const uint16_t* buf, size_t runStart, size_t runLength,
size_t bufSize, bool isRtl, LayoutContext* ctx, size_t dstStart,
const std::shared_ptr<FontCollection>& collection, Layout* layout, float* advances);
// Lay out a single word
static float doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
bool isRtl, LayoutContext* ctx, size_t bufStart,
const std::shared_ptr<FontCollection>& collection, Layout* layout, float* advances);
// Lay out a single bidi run
void doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
bool isRtl, LayoutContext* ctx, const std::shared_ptr<FontCollection>& collection);
// Append another layout (for example, cached value) into this one
void appendLayout(Layout* src, size_t start, float extraAdvance);
std::vector<LayoutGlyph> mGlyphs;
std::vector<float> mAdvances;
std::vector<FakedFont> mFaces;
float mAdvance;
MinikinRect mBounds;
};
} // namespace minikin
#endif // MINIKIN_LAYOUT_H