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:
reed 2014-10-22 13:20:58 -07:00 committed by Commit bot
parent f0b1710bdb
commit a0c814cffb
5 changed files with 168 additions and 8 deletions

View File

@ -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

View File

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

View File

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

View File

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