60a0e87c6c
Bug: skia: Change-Id: I4cc66e19ceab7914b8895e23c21860842c9fadbf Reviewed-on: https://skia-review.googlesource.com/c/181164 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Mike Reed <reed@google.com> Auto-Submit: Mike Reed <reed@google.com>
268 lines
8.2 KiB
C++
268 lines
8.2 KiB
C++
/*
|
|
* Copyright 2018 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#ifndef SkTextBlobPriv_DEFINED
|
|
#define SkTextBlobPriv_DEFINED
|
|
|
|
#include "SkColorFilter.h"
|
|
#include "SkDrawLooper.h"
|
|
#include "SkFont.h"
|
|
#include "SkImageFilter.h"
|
|
#include "SkMaskFilter.h"
|
|
#include "SkPaintPriv.h"
|
|
#include "SkPathEffect.h"
|
|
#include "SkSafeMath.h"
|
|
#include "SkShader.h"
|
|
#include "SkTextBlob.h"
|
|
#include "SkTypeface.h"
|
|
|
|
class SkReadBuffer;
|
|
class SkWriteBuffer;
|
|
|
|
class SkTextBlobPriv {
|
|
public:
|
|
/**
|
|
* Serialize to a buffer.
|
|
*/
|
|
static void Flatten(const SkTextBlob& , SkWriteBuffer&);
|
|
|
|
/**
|
|
* Recreate an SkTextBlob that was serialized into a buffer.
|
|
*
|
|
* @param SkReadBuffer Serialized blob data.
|
|
* @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
|
|
* invalid.
|
|
*/
|
|
static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
|
|
};
|
|
|
|
class SkTextBlobBuilderPriv {
|
|
public:
|
|
static const SkTextBlobBuilder::RunBuffer& AllocRunText(SkTextBlobBuilder* builder,
|
|
const SkFont& font, int count, SkScalar x, SkScalar y, int textByteCount,
|
|
SkString lang, const SkRect* bounds = nullptr) {
|
|
return builder->allocRunText(font, count, x, y, textByteCount, lang, bounds);
|
|
}
|
|
static const SkTextBlobBuilder::RunBuffer& AllocRunTextPosH(SkTextBlobBuilder* builder,
|
|
const SkFont& font, int count, SkScalar y, int textByteCount, SkString lang,
|
|
const SkRect* bounds = nullptr) {
|
|
return builder->allocRunTextPosH(font, count, y, textByteCount, lang, bounds);
|
|
}
|
|
static const SkTextBlobBuilder::RunBuffer& AllocRunTextPos(SkTextBlobBuilder* builder,
|
|
const SkFont& font, int count, int textByteCount, SkString lang,
|
|
const SkRect* bounds = nullptr) {
|
|
return builder->allocRunTextPos(font, count, textByteCount, lang, bounds);
|
|
}
|
|
};
|
|
|
|
//
|
|
// Textblob data is laid out into externally-managed storage as follows:
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
// | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
|
|
// -----------------------------------------------------------------------------
|
|
//
|
|
// Each run record describes a text blob run, and can be used to determine the (implicit)
|
|
// location of the following record.
|
|
//
|
|
// Extended Textblob runs have more data after the Pos[] array:
|
|
//
|
|
// -------------------------------------------------------------------------
|
|
// ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ...
|
|
// -------------------------------------------------------------------------
|
|
//
|
|
// To determine the length of the extended run data, the TextSize must be read.
|
|
//
|
|
// Extended Textblob runs may be mixed with non-extended runs.
|
|
|
|
SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
|
|
|
|
class SkTextBlob::RunRecord {
|
|
public:
|
|
RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkFont& font, GlyphPositioning pos)
|
|
: fFont(font)
|
|
, fCount(count)
|
|
, fOffset(offset)
|
|
, fFlags(pos) {
|
|
SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask);
|
|
|
|
SkDEBUGCODE(fMagic = kRunRecordMagic);
|
|
if (textSize > 0) {
|
|
fFlags |= kExtended_Flag;
|
|
*this->textSizePtr() = textSize;
|
|
}
|
|
}
|
|
|
|
uint32_t glyphCount() const {
|
|
return fCount;
|
|
}
|
|
|
|
const SkPoint& offset() const {
|
|
return fOffset;
|
|
}
|
|
|
|
const SkFont& font() const {
|
|
return fFont;
|
|
}
|
|
|
|
GlyphPositioning positioning() const {
|
|
return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
|
|
}
|
|
|
|
uint16_t* glyphBuffer() const {
|
|
static_assert(SkIsAlignPtr(sizeof(RunRecord)), "");
|
|
// Glyphs are stored immediately following the record.
|
|
return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
|
|
}
|
|
|
|
// can be aliased with pointBuffer() or xformBuffer()
|
|
SkScalar* posBuffer() const {
|
|
// Position scalars follow the (aligned) glyph buffer.
|
|
return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
|
|
SkAlign4(fCount * sizeof(uint16_t)));
|
|
}
|
|
|
|
// alias for posBuffer()
|
|
SkPoint* pointBuffer() const {
|
|
SkASSERT(this->positioning() == (GlyphPositioning)2);
|
|
return reinterpret_cast<SkPoint*>(this->posBuffer());
|
|
}
|
|
|
|
// alias for posBuffer()
|
|
SkRSXform* xformBuffer() const {
|
|
SkASSERT(this->positioning() == (GlyphPositioning)3);
|
|
return reinterpret_cast<SkRSXform*>(this->posBuffer());
|
|
}
|
|
|
|
uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
|
|
|
|
uint32_t* clusterBuffer() const {
|
|
// clusters follow the textSize.
|
|
return isExtended() ? 1 + this->textSizePtr() : nullptr;
|
|
}
|
|
|
|
char* textBuffer() const {
|
|
return isExtended()
|
|
? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
|
|
: nullptr;
|
|
}
|
|
|
|
static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
|
|
SkTextBlob::GlyphPositioning positioning,
|
|
SkSafeMath* safe);
|
|
|
|
static const RunRecord* First(const SkTextBlob* blob);
|
|
|
|
static const RunRecord* Next(const RunRecord* run);
|
|
|
|
void validate(const uint8_t* storageTop) const;
|
|
|
|
private:
|
|
friend class SkTextBlobBuilder;
|
|
|
|
enum Flags {
|
|
kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
|
|
kLast_Flag = 0x04, // set for the last blob run
|
|
kExtended_Flag = 0x08, // set for runs with text/cluster info
|
|
};
|
|
|
|
static const RunRecord* NextUnchecked(const RunRecord* run);
|
|
|
|
static size_t PosCount(uint32_t glyphCount,
|
|
SkTextBlob::GlyphPositioning positioning,
|
|
SkSafeMath* safe);
|
|
|
|
uint32_t* textSizePtr() const;
|
|
|
|
void grow(uint32_t count);
|
|
|
|
bool isExtended() const {
|
|
return fFlags & kExtended_Flag;
|
|
}
|
|
|
|
SkFont fFont;
|
|
uint32_t fCount;
|
|
SkPoint fOffset;
|
|
uint32_t fFlags;
|
|
|
|
SkDEBUGCODE(unsigned fMagic;)
|
|
};
|
|
|
|
/**
|
|
* Iterate through all of the text runs of the text blob. For example:
|
|
* for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
|
|
* .....
|
|
* }
|
|
*/
|
|
class SkTextBlobRunIterator {
|
|
public:
|
|
SkTextBlobRunIterator(const SkTextBlob* blob);
|
|
|
|
enum GlyphPositioning : uint8_t {
|
|
kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph.
|
|
kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph.
|
|
kFull_Positioning = 2, // Point positioning -- two scalars per glyph.
|
|
kRSXform_Positioning = 3, // RSXform positioning -- four scalars per glyph.
|
|
};
|
|
|
|
bool done() const {
|
|
return !fCurrentRun;
|
|
}
|
|
void next();
|
|
|
|
uint32_t glyphCount() const {
|
|
SkASSERT(!this->done());
|
|
return fCurrentRun->glyphCount();
|
|
}
|
|
const uint16_t* glyphs() const {
|
|
SkASSERT(!this->done());
|
|
return fCurrentRun->glyphBuffer();
|
|
}
|
|
const SkScalar* pos() const {
|
|
SkASSERT(!this->done());
|
|
return fCurrentRun->posBuffer();
|
|
}
|
|
// alias for pos()
|
|
const SkPoint* points() const {
|
|
return fCurrentRun->pointBuffer();
|
|
}
|
|
// alias for pos()
|
|
const SkRSXform* xforms() const {
|
|
return fCurrentRun->xformBuffer();
|
|
}
|
|
const SkPoint& offset() const {
|
|
SkASSERT(!this->done());
|
|
return fCurrentRun->offset();
|
|
}
|
|
const SkFont& font() const {
|
|
SkASSERT(!this->done());
|
|
return fCurrentRun->font();
|
|
}
|
|
GlyphPositioning positioning() const;
|
|
uint32_t* clusters() const {
|
|
SkASSERT(!this->done());
|
|
return fCurrentRun->clusterBuffer();
|
|
}
|
|
uint32_t textSize() const {
|
|
SkASSERT(!this->done());
|
|
return fCurrentRun->textSize();
|
|
}
|
|
char* text() const {
|
|
SkASSERT(!this->done());
|
|
return fCurrentRun->textBuffer();
|
|
}
|
|
|
|
bool isLCD() const;
|
|
|
|
private:
|
|
const SkTextBlob::RunRecord* fCurrentRun;
|
|
|
|
SkDEBUGCODE(uint8_t* fStorageTop;)
|
|
};
|
|
|
|
#endif // SkTextBlobPriv_DEFINED
|