Add SkTypeface::getBounds()
mirrored from https://codereview.chromium.org/666303002/ BUG=skia: TBR= Review URL: https://codereview.chromium.org/676523002
This commit is contained in:
parent
f0b1710bdb
commit
a0c814cffb
@ -15,6 +15,13 @@
|
||||
#include "SkTypeface_win.h"
|
||||
#endif
|
||||
|
||||
static void scale(SkRect* rect, SkScalar scale) {
|
||||
rect->fLeft *= scale;
|
||||
rect->fTop *= scale;
|
||||
rect->fRight *= scale;
|
||||
rect->fBottom *= scale;
|
||||
}
|
||||
|
||||
// limit this just so we don't take too long to draw
|
||||
#define MAX_FAMILIES 30
|
||||
|
||||
@ -220,9 +227,96 @@ private:
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
class FontMgrBoundsGM : public skiagm::GM {
|
||||
public:
|
||||
FontMgrBoundsGM() {
|
||||
fName.set("fontmgr_bounds");
|
||||
fFM.reset(SkFontMgr::RefDefault());
|
||||
}
|
||||
|
||||
static void show_bounds(SkCanvas* canvas, const SkPaint& paint, SkScalar x, SkScalar y,
|
||||
SkColor boundsColor) {
|
||||
const char str[] = "jyHO[]{}@-_&%$";
|
||||
|
||||
const SkTypeface* tf = paint.getTypeface();
|
||||
for (int i = 0; str[i]; ++i) {
|
||||
canvas->drawText(&str[i], 1, x, y, paint);
|
||||
}
|
||||
|
||||
SkRect r = tf->getBounds();
|
||||
scale(&r, paint.getTextSize());
|
||||
r.offset(x, y);
|
||||
SkPaint p(paint);
|
||||
p.setColor(boundsColor);
|
||||
canvas->drawRect(r, p);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual SkString onShortName() {
|
||||
return fName;
|
||||
}
|
||||
|
||||
virtual SkISize onISize() {
|
||||
return SkISize::Make(1024, 850);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setSubpixelText(true);
|
||||
paint.setTextSize(100);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
|
||||
const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE };
|
||||
|
||||
SkFontMgr* fm = fFM;
|
||||
int count = SkMin32(fm->countFamilies(), 32);
|
||||
|
||||
int index = 0;
|
||||
SkScalar x = 0, y = 0;
|
||||
|
||||
canvas->translate(80, 120);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i));
|
||||
for (int j = 0; j < set->count(); ++j) {
|
||||
SkSafeUnref(paint.setTypeface(set->createTypeface(j)));
|
||||
if (paint.getTypeface()) {
|
||||
show_bounds(canvas, paint, x, y, boundsColors[index & 1]);
|
||||
index += 1;
|
||||
x += 160;
|
||||
if (0 == (index % 6)) {
|
||||
x = 0;
|
||||
y += 160;
|
||||
}
|
||||
if (index >= 30) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint32_t onGetFlags() const SK_OVERRIDE {
|
||||
// fontdescriptors (and therefore serialization) don't yet understand
|
||||
// these new styles, so skip tests that exercise that for now.
|
||||
|
||||
// If certain fonts are picked up (e.g. Microsoft Jhenghei 20MB for Regular, 12MB for Bold),
|
||||
// the resulting pdf can be ~700MB and crashes Chrome's PDF viewer.
|
||||
|
||||
return kSkipPicture_Flag | kSkipPipe_Flag | kSkipPDF_Flag;
|
||||
}
|
||||
|
||||
private:
|
||||
SkAutoTUnref<SkFontMgr> fFM;
|
||||
SkString fName;
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_GM( return SkNEW(FontMgrGM); )
|
||||
DEF_GM( return SkNEW(FontMgrBoundsGM); )
|
||||
DEF_GM( return SkNEW(FontMgrMatchGM); )
|
||||
|
||||
#ifdef SK_BUILD_FOR_WIN
|
||||
|
@ -147,19 +147,19 @@ public:
|
||||
SkLazyPtr() : fPtr(NULL) {}
|
||||
~SkLazyPtr() { if (fPtr) { Destroy((T*)fPtr); } }
|
||||
|
||||
T* get() {
|
||||
T* get() const {
|
||||
T* ptr = (T*)sk_consume_load(&fPtr);
|
||||
return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, SkNEW(T));
|
||||
}
|
||||
|
||||
template <typename Create>
|
||||
T* get(const Create& create) {
|
||||
T* get(const Create& create) const {
|
||||
T* ptr = (T*)sk_consume_load(&fPtr);
|
||||
return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, create());
|
||||
}
|
||||
|
||||
private:
|
||||
void* fPtr;
|
||||
mutable void* fPtr;
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "SkAdvancedTypefaceMetrics.h"
|
||||
#include "SkFontStyle.h"
|
||||
#include "SkLazyPtr.h"
|
||||
#include "SkWeakRefCnt.h"
|
||||
|
||||
class SkDescriptor;
|
||||
@ -282,6 +283,13 @@ public:
|
||||
SkScalerContext* createScalerContext(const SkDescriptor*,
|
||||
bool allowFailure = false) const;
|
||||
|
||||
/**
|
||||
* Return a rectangle (scaled to 1-pt) that represents the union of the bounds of all
|
||||
* of the glyphs, but each one positioned at (0,). This may be conservatively large, and
|
||||
* will not take into account any hinting or other size-specific adjustments.
|
||||
*/
|
||||
SkRect getBounds() const;
|
||||
|
||||
// PRIVATE / EXPERIMENTAL -- do not call
|
||||
void filterRec(SkScalerContextRec* rec) const {
|
||||
this->onFilterRec(rec);
|
||||
@ -333,6 +341,8 @@ protected:
|
||||
virtual size_t onGetTableData(SkFontTableTag, size_t offset,
|
||||
size_t length, void* data) const = 0;
|
||||
|
||||
virtual bool onComputeBounds(SkRect*) const;
|
||||
|
||||
private:
|
||||
friend class SkGTypeface;
|
||||
friend class SkPDFFont;
|
||||
@ -359,6 +369,10 @@ private:
|
||||
static SkTypeface* CreateDefault(int style); // SkLazyPtr requires an int, not a Style.
|
||||
static void DeleteDefault(SkTypeface*);
|
||||
|
||||
struct BoundsComputer;
|
||||
// friend struct BoundsComputer;
|
||||
|
||||
SkLazyPtr<SkRect> fLazyBounds;
|
||||
SkFontID fUniqueID;
|
||||
SkFontStyle fStyle;
|
||||
bool fIsFixedPitch;
|
||||
|
@ -278,9 +278,61 @@ SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkTypeface::onGetKerningPairAdjustments(const uint16_t glyphs[], int count,
|
||||
int32_t adjustments[]) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkDescriptor.h"
|
||||
#include "SkPaint.h"
|
||||
|
||||
struct SkTypeface::BoundsComputer {
|
||||
const SkTypeface& fTypeface;
|
||||
|
||||
BoundsComputer(const SkTypeface& tf) : fTypeface(tf) {}
|
||||
|
||||
SkRect* operator()() const {
|
||||
SkRect* rect = SkNEW(SkRect);
|
||||
if (!fTypeface.onComputeBounds(rect)) {
|
||||
rect->setEmpty();
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
};
|
||||
|
||||
SkRect SkTypeface::getBounds() const {
|
||||
return *fLazyBounds.get(BoundsComputer(*this));
|
||||
}
|
||||
|
||||
bool SkTypeface::onComputeBounds(SkRect* bounds) const {
|
||||
// we use a big size to ensure lots of significant bits from the scalercontext.
|
||||
// then we scale back down to return our final answer (at 1-pt)
|
||||
const SkScalar textSize = 2048;
|
||||
const SkScalar invTextSize = 1 / textSize;
|
||||
|
||||
SkPaint paint;
|
||||
paint.setTypeface(const_cast<SkTypeface*>(this));
|
||||
paint.setTextSize(textSize);
|
||||
paint.setLinearText(true);
|
||||
|
||||
SkScalerContext::Rec rec;
|
||||
SkScalerContext::MakeRec(paint, NULL, NULL, &rec);
|
||||
|
||||
SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
|
||||
SkDescriptor* desc = ad.getDesc();
|
||||
desc->init();
|
||||
desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
|
||||
|
||||
SkAutoTDelete<SkScalerContext> ctx(this->createScalerContext(desc, true));
|
||||
if (ctx.get()) {
|
||||
SkPaint::FontMetrics fm;
|
||||
ctx->getFontMetrics(&fm);
|
||||
bounds->set(fm.fXMin * invTextSize, fm.fTop * invTextSize,
|
||||
fm.fXMax * invTextSize, fm.fBottom * invTextSize);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user