Move distance field generation to the glyph cache.
Distance fields are currently created in GrTextStrike, which is the wrong place. This moves that to the glyph cache where it belongs. As part of my testing, I found that when we fall back to paths in the GrDistanceFieldTextContext it was not scaling them properly, so that's fixed in here too. R=robertphillips@google.com, reed@google.com Author: jvanverth@google.com Review URL: https://codereview.chromium.org/227593010 git-svn-id: http://skia.googlecode.com/svn/trunk@14193 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
73b55eb7d7
commit
762cd80437
@ -29,6 +29,12 @@ public:
|
||||
virtual bool getPackedGlyphBounds(GrGlyph::PackedID, SkIRect* bounds) = 0;
|
||||
virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height,
|
||||
int rowBytes, void* image) = 0;
|
||||
// get bounds for distance field associated with packed ID
|
||||
virtual bool getPackedGlyphDFBounds(GrGlyph::PackedID, SkIRect* bounds) = 0;
|
||||
// copies distance field bytes into pre-allocated dfImage
|
||||
// (should be width*height bytes in size)
|
||||
virtual bool getPackedGlyphDFImage(GrGlyph::PackedID, int width, int height,
|
||||
void* dfImage) = 0;
|
||||
virtual bool getGlyphPath(uint16_t glyphID, SkPath*) = 0;
|
||||
|
||||
private:
|
||||
|
@ -83,9 +83,12 @@ public:
|
||||
// overrides
|
||||
virtual const GrKey* getKey();
|
||||
virtual GrMaskFormat getMaskFormat();
|
||||
virtual bool getPackedGlyphBounds(GrGlyph::PackedID, SkIRect* bounds);
|
||||
virtual bool getPackedGlyphBounds(GrGlyph::PackedID, SkIRect* bounds) SK_OVERRIDE;
|
||||
virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height,
|
||||
int rowBytes, void* image);
|
||||
int rowBytes, void* image) SK_OVERRIDE;
|
||||
virtual bool getPackedGlyphDFBounds(GrGlyph::PackedID, SkIRect* bounds) SK_OVERRIDE;
|
||||
virtual bool getPackedGlyphDFImage(GrGlyph::PackedID, int width, int height,
|
||||
void* image) SK_OVERRIDE;
|
||||
virtual bool getGlyphPath(uint16_t glyphID, SkPath*);
|
||||
|
||||
private:
|
||||
|
@ -327,19 +327,17 @@ static unsigned char pack_distance_field_val(float dist, float distanceMagnitude
|
||||
}
|
||||
#endif
|
||||
|
||||
// assumes an 8-bit image and distance field
|
||||
bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField,
|
||||
const unsigned char* image,
|
||||
int width, int height,
|
||||
int distanceMagnitude) {
|
||||
// assumes a padded 8-bit image and distance field
|
||||
// width and height are the original width and height of the image
|
||||
bool generate_distance_field_from_image(unsigned char* distanceField,
|
||||
const unsigned char* copyPtr,
|
||||
int width, int height) {
|
||||
SkASSERT(NULL != distanceField);
|
||||
SkASSERT(NULL != image);
|
||||
SkASSERT(NULL != copyPtr);
|
||||
|
||||
// the final distance field will have additional texels on each side to handle
|
||||
// the maximum distance + 1 for bilerp
|
||||
// we expand our temp data by one more on each side to simplify
|
||||
// the scanning code -- will always be treated as infinitely far away
|
||||
int pad = distanceMagnitude+2;
|
||||
int pad = SK_DistanceFieldPad + 1;
|
||||
|
||||
// set params for distance field data
|
||||
int dataWidth = width + 2*pad;
|
||||
@ -355,27 +353,10 @@ bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField,
|
||||
unsigned char* edgePtr = (unsigned char*) edgeStorage.get();
|
||||
sk_bzero(edgePtr, dataWidth*dataHeight*sizeof(char));
|
||||
|
||||
SkAutoSMalloc<1024> copyStorage((width+2)*(height+2)*sizeof(char));
|
||||
unsigned char* copyPtr = (unsigned char*) copyStorage.get();
|
||||
|
||||
// we copy our source image into a padded copy to ensure we catch edge transitions
|
||||
// around the outside
|
||||
const unsigned char* currImage = image;
|
||||
sk_bzero(copyPtr, (width+2)*sizeof(char));
|
||||
unsigned char* currCopy = copyPtr + width + 2;
|
||||
for (int i = 0; i < height; ++i) {
|
||||
*currCopy++ = 0;
|
||||
memcpy(currCopy, currImage, width*sizeof(char));
|
||||
currImage += width;
|
||||
currCopy += width;
|
||||
*currCopy++ = 0;
|
||||
}
|
||||
sk_bzero(currCopy, (width+2)*sizeof(char));
|
||||
|
||||
// copy glyph into distance field storage
|
||||
init_glyph_data(dataPtr, edgePtr, copyPtr,
|
||||
dataWidth, dataHeight,
|
||||
width+2, height+2, pad-1);
|
||||
width+2, height+2, SK_DistanceFieldPad);
|
||||
|
||||
// create initial distance data, particularly at edges
|
||||
init_distances(dataPtr, edgePtr, dataWidth, dataHeight);
|
||||
@ -465,7 +446,7 @@ bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField,
|
||||
} else {
|
||||
dist = SkScalarSqrt(currData->fDistSq);
|
||||
}
|
||||
*dfPtr++ = pack_distance_field_val(dist, (float)distanceMagnitude);
|
||||
*dfPtr++ = pack_distance_field_val(dist, (float)SK_DistanceFieldMagnitude);
|
||||
#endif
|
||||
++currData;
|
||||
++currEdge;
|
||||
@ -476,3 +457,65 @@ bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// assumes an 8-bit image and distance field
|
||||
bool SkGenerateDistanceFieldFromA8Image(unsigned char* distanceField,
|
||||
const unsigned char* image,
|
||||
int width, int height, int rowBytes) {
|
||||
SkASSERT(NULL != distanceField);
|
||||
SkASSERT(NULL != image);
|
||||
|
||||
// create temp data
|
||||
SkAutoSMalloc<1024> copyStorage((width+2)*(height+2)*sizeof(char));
|
||||
unsigned char* copyPtr = (unsigned char*) copyStorage.get();
|
||||
|
||||
// we copy our source image into a padded copy to ensure we catch edge transitions
|
||||
// around the outside
|
||||
const unsigned char* currSrcScanLine = image;
|
||||
sk_bzero(copyPtr, (width+2)*sizeof(char));
|
||||
unsigned char* currDestPtr = copyPtr + width + 2;
|
||||
for (int i = 0; i < height; ++i) {
|
||||
*currDestPtr++ = 0;
|
||||
memcpy(currDestPtr, currSrcScanLine, rowBytes);
|
||||
currSrcScanLine += rowBytes;
|
||||
currDestPtr += width;
|
||||
*currDestPtr++ = 0;
|
||||
}
|
||||
sk_bzero(currDestPtr, (width+2)*sizeof(char));
|
||||
|
||||
return generate_distance_field_from_image(distanceField, copyPtr, width, height);
|
||||
}
|
||||
|
||||
// assumes a 1-bit image and 8-bit distance field
|
||||
bool SkGenerateDistanceFieldFromBWImage(unsigned char* distanceField,
|
||||
const unsigned char* image,
|
||||
int width, int height, int rowBytes) {
|
||||
SkASSERT(NULL != distanceField);
|
||||
SkASSERT(NULL != image);
|
||||
|
||||
// create temp data
|
||||
SkAutoSMalloc<1024> copyStorage((width+2)*(height+2)*sizeof(char));
|
||||
unsigned char* copyPtr = (unsigned char*) copyStorage.get();
|
||||
|
||||
// we copy our source image into a padded copy to ensure we catch edge transitions
|
||||
// around the outside
|
||||
const unsigned char* currSrcScanLine = image;
|
||||
sk_bzero(copyPtr, (width+2)*sizeof(char));
|
||||
unsigned char* currDestPtr = copyPtr + width + 2;
|
||||
for (int i = 0; i < height; ++i) {
|
||||
*currDestPtr++ = 0;
|
||||
int rowWritesLeft = width;
|
||||
const unsigned char *maskPtr = currSrcScanLine;
|
||||
while (rowWritesLeft > 0) {
|
||||
unsigned mask = *maskPtr++;
|
||||
for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
|
||||
*currDestPtr++ = (mask & (1 << i)) ? 0xff : 0;
|
||||
}
|
||||
}
|
||||
currSrcScanLine += rowBytes;
|
||||
*currDestPtr++ = 0;
|
||||
}
|
||||
sk_bzero(currDestPtr, (width+2)*sizeof(char));
|
||||
|
||||
return generate_distance_field_from_image(distanceField, copyPtr, width, height);
|
||||
}
|
||||
|
@ -7,19 +7,54 @@
|
||||
#ifndef SkDistanceFieldGen_DEFINED
|
||||
#define SkDistanceFieldGen_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
// the max magnitude for the distance field
|
||||
// distance values are limited to the range [-SK_DistanceFieldMagnitude, SK_DistanceFieldMagnitude)
|
||||
#define SK_DistanceFieldMagnitude 4
|
||||
// we need to pad around the original glyph to allow our maximum distance of
|
||||
// SK_DistanceFieldMagnitude texels away from any edge
|
||||
// we add one to this pad to allow for bilerp
|
||||
#define SK_DistanceFieldPad (SK_DistanceFieldMagnitude+1)
|
||||
|
||||
// for the fragment shader
|
||||
// The distance field is constructed as unsigned char values, so that the zero value is at 128,
|
||||
// and the range is [-4, 4 - 1/255). Hence our multiplier is 8 - 1/32 and zero threshold is 128/255.
|
||||
#define SK_DistanceFieldMultiplier "7.96875"
|
||||
#define SK_DistanceFieldThreshold "0.50196078431"
|
||||
|
||||
/** Given 8-bit mask data, generate the associated distance field
|
||||
|
||||
* @param distanceField The distance field to be generated. Should already be allocated
|
||||
* by the client with the padding below.
|
||||
* by the client with the padding above.
|
||||
* @param image 8-bit mask we're using to generate the distance field.
|
||||
* @param w Width of the image.
|
||||
* @param h Height of the image.
|
||||
* @param distanceMagnitude Largest possible absolute value for the distance. The distance field
|
||||
* will be padded to w + 2*distanceMagnitude, h + 2*distanceMagnitude.
|
||||
* @param w Width of the original image.
|
||||
* @param h Height of the original image.
|
||||
* @param rowBytes Size of each row in the image, in bytes
|
||||
*/
|
||||
bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField,
|
||||
const unsigned char* image,
|
||||
int w, int h,
|
||||
int distanceMagnitude);
|
||||
bool SkGenerateDistanceFieldFromA8Image(unsigned char* distanceField,
|
||||
const unsigned char* image,
|
||||
int w, int h, int rowBytes);
|
||||
|
||||
/** Given 1-bit mask data, generate the associated distance field
|
||||
|
||||
* @param distanceField The distance field to be generated. Should already be allocated
|
||||
* by the client with the padding above.
|
||||
* @param image 1-bit mask we're using to generate the distance field.
|
||||
* @param w Width of the original image.
|
||||
* @param h Height of the original image.
|
||||
* @param rowBytes Size of each row in the image, in bytes
|
||||
*/
|
||||
bool SkGenerateDistanceFieldFromBWImage(unsigned char* distanceField,
|
||||
const unsigned char* image,
|
||||
int w, int h, int rowBytes);
|
||||
|
||||
/** Given width and height of original image, return size (in bytes) of distance field
|
||||
* @param w Width of the original image.
|
||||
* @param h Height of the original image.
|
||||
*/
|
||||
inline size_t SkComputeDistanceFieldSize(int w, int h) {
|
||||
return (w + 2*SK_DistanceFieldPad) * (h + 2*SK_DistanceFieldPad) * sizeof(unsigned char);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -29,6 +29,7 @@ struct SkGlyph {
|
||||
uint16_t fWidth, fHeight;
|
||||
int16_t fTop, fLeft;
|
||||
|
||||
void* fDistanceField;
|
||||
uint8_t fMaskFormat;
|
||||
int8_t fRsbDelta, fLsbDelta; // used by auto-kerning
|
||||
|
||||
@ -36,6 +37,7 @@ struct SkGlyph {
|
||||
fID = id;
|
||||
fImage = NULL;
|
||||
fPath = NULL;
|
||||
fDistanceField = NULL;
|
||||
fMaskFormat = MASK_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
|
47
src/core/SkGlyphCache.cpp
Normal file → Executable file
47
src/core/SkGlyphCache.cpp
Normal file → Executable file
@ -9,6 +9,7 @@
|
||||
|
||||
#include "SkGlyphCache.h"
|
||||
#include "SkGlyphCache_Globals.h"
|
||||
#include "SkDistanceFieldGen.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPath.h"
|
||||
@ -328,12 +329,12 @@ SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) {
|
||||
|
||||
const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
|
||||
if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) {
|
||||
if (glyph.fImage == NULL) {
|
||||
if (NULL == glyph.fImage) {
|
||||
size_t size = glyph.computeImageSize();
|
||||
const_cast<SkGlyph&>(glyph).fImage = fGlyphAlloc.alloc(size,
|
||||
SkChunkAlloc::kReturnNil_AllocFailType);
|
||||
// check that alloc() actually succeeded
|
||||
if (glyph.fImage) {
|
||||
if (NULL != glyph.fImage) {
|
||||
fScalerContext->getImage(glyph);
|
||||
// TODO: the scaler may have changed the maskformat during
|
||||
// getImage (e.g. from AA or LCD to BW) which means we may have
|
||||
@ -358,6 +359,45 @@ const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
|
||||
return glyph.fPath;
|
||||
}
|
||||
|
||||
const void* SkGlyphCache::findDistanceField(const SkGlyph& glyph) {
|
||||
if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) {
|
||||
if (NULL == glyph.fDistanceField) {
|
||||
size_t size = SkComputeDistanceFieldSize(glyph.fWidth, glyph.fHeight);
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
const void* image = this->findImage(glyph);
|
||||
// now generate the distance field
|
||||
if (NULL != image) {
|
||||
const_cast<SkGlyph&>(glyph).fDistanceField = fGlyphAlloc.alloc(size,
|
||||
SkChunkAlloc::kReturnNil_AllocFailType);
|
||||
if (NULL != glyph.fDistanceField) {
|
||||
SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
|
||||
if (SkMask::kA8_Format == maskFormat) {
|
||||
// make the distance field from the image
|
||||
SkGenerateDistanceFieldFromA8Image((unsigned char*)glyph.fDistanceField,
|
||||
(unsigned char*)glyph.fImage,
|
||||
glyph.fWidth, glyph.fHeight,
|
||||
glyph.rowBytes());
|
||||
fMemoryUsed += size;
|
||||
} else if (SkMask::kBW_Format == maskFormat) {
|
||||
// make the distance field from the image
|
||||
SkGenerateDistanceFieldFromBWImage((unsigned char*)glyph.fDistanceField,
|
||||
(unsigned char*)glyph.fImage,
|
||||
glyph.fWidth, glyph.fHeight,
|
||||
glyph.rowBytes());
|
||||
fMemoryUsed += size;
|
||||
} else {
|
||||
fGlyphAlloc.unalloc(glyph.fDistanceField);
|
||||
const_cast<SkGlyph&>(glyph).fDistanceField = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return glyph.fDistanceField;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const {
|
||||
@ -649,6 +689,9 @@ void SkGlyphCache::validate() const {
|
||||
if (glyph->fImage) {
|
||||
SkASSERT(fGlyphAlloc.contains(glyph->fImage));
|
||||
}
|
||||
if (glyph->fDistanceField) {
|
||||
SkASSERT(fGlyphAlloc.contains(glyph->fDistanceField));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -92,6 +92,10 @@ public:
|
||||
this will trigger that.
|
||||
*/
|
||||
const SkPath* findPath(const SkGlyph&);
|
||||
/** Return the distance field associated with the glyph. If it has not been generated
|
||||
this will trigger that.
|
||||
*/
|
||||
const void* findDistanceField(const SkGlyph&);
|
||||
|
||||
/** Return the vertical metrics for this strike.
|
||||
*/
|
||||
|
@ -239,10 +239,11 @@ void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
|
||||
}
|
||||
|
||||
GrContext::AutoMatrix am;
|
||||
SkMatrix translate;
|
||||
translate.setTranslate(sx, sy);
|
||||
SkMatrix ctm;
|
||||
ctm.setScale(fTextRatio, fTextRatio);
|
||||
ctm.postTranslate(sx, sy);
|
||||
GrPaint tmpPaint(fPaint);
|
||||
am.setPreConcat(fContext, translate, &tmpPaint);
|
||||
am.setPreConcat(fContext, ctm, &tmpPaint);
|
||||
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
||||
fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
|
||||
return;
|
||||
|
@ -214,10 +214,6 @@ void GrFontCache::dump() const {
|
||||
static int gCounter;
|
||||
#endif
|
||||
|
||||
// this acts as the max magnitude for the distance field,
|
||||
// as well as the pad we need around the glyph
|
||||
#define DISTANCE_FIELD_RANGE 4
|
||||
|
||||
/*
|
||||
The text strike is specific to a given font/style/matrix setup, which is
|
||||
represented by the GrHostFontScaler object we are given in getGlyph().
|
||||
@ -260,20 +256,17 @@ GrTextStrike::~GrTextStrike() {
|
||||
GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
|
||||
GrFontScaler* scaler) {
|
||||
SkIRect bounds;
|
||||
if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
|
||||
return NULL;
|
||||
if (fUseDistanceField) {
|
||||
if (!scaler->getPackedGlyphDFBounds(packed, &bounds)) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GrGlyph* glyph = fPool.alloc();
|
||||
// expand bounds to hold full distance field data
|
||||
// + room for bilerp
|
||||
int pad = DISTANCE_FIELD_RANGE+1;
|
||||
if (fUseDistanceField) {
|
||||
bounds.fLeft -= pad;
|
||||
bounds.fRight += pad;
|
||||
bounds.fTop -= pad;
|
||||
bounds.fBottom += pad;
|
||||
}
|
||||
glyph->init(packed, bounds);
|
||||
fCache.insert(packed, glyph);
|
||||
return glyph;
|
||||
@ -306,56 +299,27 @@ bool GrTextStrike::addGlyphToAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
|
||||
|
||||
int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
|
||||
|
||||
GrPlot* plot;
|
||||
size_t size = glyph->fBounds.area() * bytesPerPixel;
|
||||
SkAutoSMalloc<1024> storage(size);
|
||||
if (fUseDistanceField) {
|
||||
// we've already expanded the glyph dimensions to match the final size
|
||||
// but must shrink back down to get the packed glyph data
|
||||
int dfWidth = glyph->width();
|
||||
int dfHeight = glyph->height();
|
||||
int pad = DISTANCE_FIELD_RANGE+1;
|
||||
int width = dfWidth - 2*pad;
|
||||
int height = dfHeight - 2*pad;
|
||||
int stride = width*bytesPerPixel;
|
||||
|
||||
size_t size = width * height * bytesPerPixel;
|
||||
SkAutoSMalloc<1024> storage(size);
|
||||
if (!scaler->getPackedGlyphImage(glyph->fPackedID, width, height, stride, storage.get())) {
|
||||
if (!scaler->getPackedGlyphDFImage(glyph->fPackedID, glyph->width(),
|
||||
glyph->height(),
|
||||
storage.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// alloc storage for distance field glyph
|
||||
size_t dfSize = dfWidth * dfHeight * bytesPerPixel;
|
||||
SkAutoSMalloc<1024> dfStorage(dfSize);
|
||||
|
||||
if (1 == bytesPerPixel) {
|
||||
(void) SkGenerateDistanceFieldFromImage((unsigned char*)dfStorage.get(),
|
||||
(unsigned char*)storage.get(),
|
||||
width, height, DISTANCE_FIELD_RANGE);
|
||||
} else {
|
||||
// distance fields should only be used to represent alpha masks
|
||||
SkASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy to atlas
|
||||
plot = fAtlasMgr->addToAtlas(&fAtlas, dfWidth, dfHeight, dfStorage.get(),
|
||||
&glyph->fAtlasLocation);
|
||||
|
||||
} else {
|
||||
size_t size = glyph->fBounds.area() * bytesPerPixel;
|
||||
SkAutoSMalloc<1024> storage(size);
|
||||
if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
|
||||
glyph->height(),
|
||||
glyph->width() * bytesPerPixel,
|
||||
storage.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
plot = fAtlasMgr->addToAtlas(&fAtlas, glyph->width(),
|
||||
glyph->height(), storage.get(),
|
||||
&glyph->fAtlasLocation);
|
||||
}
|
||||
|
||||
GrPlot* plot = fAtlasMgr->addToAtlas(&fAtlas, glyph->width(),
|
||||
glyph->height(), storage.get(),
|
||||
&glyph->fAtlasLocation);
|
||||
|
||||
if (NULL == plot) {
|
||||
return false;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "GrTemplates.h"
|
||||
#include "SkGr.h"
|
||||
#include "SkDescriptor.h"
|
||||
#include "SkDistanceFieldGen.h"
|
||||
#include "SkGlyphCache.h"
|
||||
|
||||
class SkGrDescKey : public GrKey {
|
||||
@ -102,14 +103,23 @@ const GrKey* SkGrFontScaler::getKey() {
|
||||
return fKey;
|
||||
}
|
||||
|
||||
bool SkGrFontScaler::getPackedGlyphBounds(GrGlyph::PackedID packed,
|
||||
SkIRect* bounds) {
|
||||
bool SkGrFontScaler::getPackedGlyphBounds(GrGlyph::PackedID packed, SkIRect* bounds) {
|
||||
const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
|
||||
GrGlyph::UnpackFixedX(packed),
|
||||
GrGlyph::UnpackFixedY(packed));
|
||||
GrGlyph::UnpackFixedX(packed),
|
||||
GrGlyph::UnpackFixedY(packed));
|
||||
bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkGrFontScaler::getPackedGlyphDFBounds(GrGlyph::PackedID packed, SkIRect* bounds) {
|
||||
const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
|
||||
GrGlyph::UnpackFixedX(packed),
|
||||
GrGlyph::UnpackFixedY(packed));
|
||||
bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
|
||||
bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -142,8 +152,8 @@ bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
|
||||
int width, int height,
|
||||
int dstRB, void* dst) {
|
||||
const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
|
||||
GrGlyph::UnpackFixedX(packed),
|
||||
GrGlyph::UnpackFixedY(packed));
|
||||
GrGlyph::UnpackFixedX(packed),
|
||||
GrGlyph::UnpackFixedY(packed));
|
||||
SkASSERT(glyph.fWidth == width);
|
||||
SkASSERT(glyph.fHeight == height);
|
||||
const void* src = fStrike->findImage(glyph);
|
||||
@ -190,6 +200,24 @@ bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkGrFontScaler::getPackedGlyphDFImage(GrGlyph::PackedID packed,
|
||||
int width, int height,
|
||||
void* dst) {
|
||||
const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
|
||||
GrGlyph::UnpackFixedX(packed),
|
||||
GrGlyph::UnpackFixedY(packed));
|
||||
SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
|
||||
SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
|
||||
const void* src = fStrike->findDistanceField(glyph);
|
||||
if (NULL == src) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(dst, src, width * height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// we should just return const SkPath* (NULL means false)
|
||||
bool SkGrFontScaler::getGlyphPath(uint16_t glyphID, SkPath* path) {
|
||||
|
||||
|
@ -13,10 +13,7 @@
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
#include "GrTexture.h"
|
||||
|
||||
// The distance field is constructed as unsigned char values, so that the zero value is at 128,
|
||||
// and the range is [-4, 4 - 1/255). Hence our multiplier is 8 - 1/32 and zero threshold is 128/255.
|
||||
#define MULTIPLIER "7.96875"
|
||||
#define THRESHOLD "0.50196078431"
|
||||
#include "SkDistanceFieldGen.h"
|
||||
|
||||
class GrGLDistanceFieldTextureEffect : public GrGLVertexEffect {
|
||||
public:
|
||||
@ -58,7 +55,8 @@ public:
|
||||
fsCoordName.c_str(),
|
||||
kVec2f_GrSLType);
|
||||
builder->fsCodeAppend(";\n");
|
||||
builder->fsCodeAppend("\tfloat distance = " MULTIPLIER "*(texColor.r - " THRESHOLD ");\n");
|
||||
builder->fsCodeAppend("\tfloat distance = "
|
||||
SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");\n");
|
||||
|
||||
// we adjust for the effect of the transformation on the distance by using
|
||||
// the length of the gradient of the texture coordinates. We use st coordinates
|
||||
@ -239,20 +237,22 @@ public:
|
||||
builder->fsAppendTextureLookup(samplers[0], "uv", kVec2f_GrSLType);
|
||||
builder->fsCodeAppend(";\n");
|
||||
builder->fsCodeAppend("\tvec3 distance;\n");
|
||||
builder->fsCodeAppend("\tdistance.y = " MULTIPLIER "*(texColor.r - " THRESHOLD ");\n");
|
||||
builder->fsCodeAppend("\tdistance.y = "
|
||||
SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");\n");
|
||||
// red is distance to left offset
|
||||
builder->fsCodeAppend("\tvec2 uv_adjusted = uv - offset;\n");
|
||||
builder->fsCodeAppend("\ttexColor = ");
|
||||
builder->fsAppendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
|
||||
builder->fsCodeAppend(";\n");
|
||||
builder->fsCodeAppend("\tdistance.x = " MULTIPLIER "*(texColor.r - " THRESHOLD ");\n");
|
||||
builder->fsCodeAppend("\tdistance.x = "
|
||||
SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");\n");
|
||||
// blue is distance to right offset
|
||||
builder->fsCodeAppend("\tuv_adjusted = uv + offset;\n");
|
||||
builder->fsCodeAppend("\ttexColor = ");
|
||||
builder->fsAppendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
|
||||
builder->fsCodeAppend(";\n");
|
||||
builder->fsCodeAppend("\tdistance.z = " MULTIPLIER "*(texColor.r - " THRESHOLD ");\n");
|
||||
|
||||
builder->fsCodeAppend("\tdistance.z = "
|
||||
SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");\n");
|
||||
// we adjust for the effect of the transformation on the distance by using
|
||||
// the length of the gradient of the texture coordinates. We use st coordinates
|
||||
// to ensure we're mapping 1:1 from texel space to pixel space.
|
||||
|
Loading…
Reference in New Issue
Block a user