aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/SkBitmap.cpp17
-rw-r--r--src/core/SkCanvas.cpp97
-rw-r--r--src/core/SkClipStack.cpp144
-rw-r--r--src/core/SkDeque.cpp42
-rw-r--r--src/core/SkDevice.cpp9
-rw-r--r--src/core/SkScalerContext.cpp2
-rw-r--r--src/effects/SkBlurDrawLooper.cpp25
-rw-r--r--src/effects/SkBlurMask.cpp48
-rw-r--r--src/effects/SkBlurMask.h7
-rw-r--r--src/effects/SkBlurMaskFilter.cpp4
-rw-r--r--src/effects/SkEmbossMaskFilter.cpp2
-rw-r--r--src/effects/SkLayerRasterizer.cpp8
-rw-r--r--src/ports/SkFontHost_FreeType.cpp25
-rw-r--r--src/ports/SkFontHost_android.cpp39
-rw-r--r--src/ports/SkFontHost_linux.cpp36
-rw-r--r--src/ports/SkFontHost_win.cpp52
16 files changed, 440 insertions, 117 deletions
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 297e156..9e6f993 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -1334,7 +1334,14 @@ void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const {
} else {
buffer.write8(SERIALIZE_PIXELTYPE_RAW_NO_CTABLE);
}
- buffer.writePad(fPixels, this->getSize());
+ buffer.writePad(fPixels, this->getSafeSize());
+ // There is no writeZeroPad() fcn, so write individual bytes.
+ if (this->getSize() > this->getSafeSize()) {
+ size_t deltaSize = this->getSize() - this->getSafeSize();
+ // Need aligned pointer to write into due to internal implementa-
+ // tion of SkWriter32.
+ memset(buffer.reserve(SkAlign4(deltaSize)), 0, deltaSize);
+ }
} else {
buffer.write8(SERIALIZE_PIXELTYPE_NONE);
}
@@ -1351,7 +1358,6 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) {
this->setConfig((Config)config, width, height, rowBytes);
this->setIsOpaque(buffer.readBool());
- size_t size = this->getSize();
int reftype = buffer.readU8();
switch (reftype) {
case SERIALIZE_PIXELTYPE_REF_PTR: {
@@ -1373,10 +1379,13 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) {
if (SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE == reftype) {
ctable = SkNEW_ARGS(SkColorTable, (buffer));
}
+ size_t size = this->getSize();
if (this->allocPixels(ctable)) {
this->lockPixels();
- buffer.read(this->getPixels(), this->getSafeSize()); // Just read what we need.
- buffer.skip(size - this->getSafeSize()); // Keep aligned for subsequent reads.
+ // Just read what we need.
+ buffer.read(this->getPixels(), this->getSafeSize());
+ // Keep aligned for subsequent reads.
+ buffer.skip(size - this->getSafeSize());
this->unlockPixels();
} else {
buffer.skip(size); // Still skip the full-sized buffer though.
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 6126850..43634ef 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -99,7 +99,7 @@ struct DeviceCM {
}
void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip,
- SkRegion* updateClip) {
+ const SkClipStack& clipStack, SkRegion* updateClip) {
int x = fX;
int y = fY;
int width = fDevice->width();
@@ -126,7 +126,7 @@ struct DeviceCM {
SkRegion::kDifference_Op);
}
- fDevice->setMatrixClip(*fMatrix, fClip);
+ fDevice->setMatrixClip(*fMatrix, fClip, clipStack);
#ifdef SK_DEBUG
if (!fClip.isEmpty()) {
@@ -477,16 +477,16 @@ SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
SkDevice* SkCanvas::getDevice() const {
// return root device
- SkDeque::Iter iter(fMCStack);
- MCRec* rec = (MCRec*)iter.next();
+ SkDeque::F2BIter iter(fMCStack);
+ MCRec* rec = (MCRec*)iter.next();
SkASSERT(rec && rec->fLayer);
return rec->fLayer->fDevice;
}
SkDevice* SkCanvas::setDevice(SkDevice* device) {
// return root device
- SkDeque::Iter iter(fMCStack);
- MCRec* rec = (MCRec*)iter.next();
+ SkDeque::F2BIter iter(fMCStack);
+ MCRec* rec = (MCRec*)iter.next();
SkASSERT(rec && rec->fLayer);
SkDevice* rootDevice = rec->fLayer->fDevice;
@@ -528,6 +528,7 @@ SkDevice* SkCanvas::setDevice(SkDevice* device) {
while ((rec = (MCRec*)iter.next()) != NULL) {
(void)rec->fRegion->setEmpty();
}
+ fClipStack.reset();
} else {
// compute our total bounds for all devices
SkIRect bounds;
@@ -539,6 +540,7 @@ SkDevice* SkCanvas::setDevice(SkDevice* device) {
while ((rec = (MCRec*)iter.next()) != NULL) {
(void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op);
}
+ fClipStack.clipDevRect(bounds, SkRegion::kIntersect_Op);
}
return device;
}
@@ -608,7 +610,7 @@ void SkCanvas::updateDeviceCMCache() {
DeviceCM* layer = fMCRec->fTopLayer;
if (NULL == layer->fNext) { // only one layer
- layer->updateMC(totalMatrix, totalClip, NULL);
+ layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
if (fUseExternalMatrix) {
layer->updateExternalMatrix(fExternalMatrix,
fExternalInverse);
@@ -617,7 +619,7 @@ void SkCanvas::updateDeviceCMCache() {
SkRegion clip;
clip = totalClip; // make a copy
do {
- layer->updateMC(totalMatrix, clip, &clip);
+ layer->updateMC(totalMatrix, clip, fClipStack, &clip);
if (fUseExternalMatrix) {
layer->updateExternalMatrix(fExternalMatrix,
fExternalInverse);
@@ -648,6 +650,9 @@ int SkCanvas::internalSave(SaveFlags flags) {
newTop->fNext = fMCRec;
fMCRec = newTop;
+ fClipStack.save();
+ SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
+
return saveCount;
}
@@ -729,6 +734,7 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
ir = clipBounds;
}
+ fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
// early exit if the clip is now empty
if (bounds_affects_clip(flags) &&
!fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) {
@@ -775,6 +781,7 @@ void SkCanvas::internalRestore() {
fLocalBoundsCompareTypeDirty = true;
fLocalBoundsCompareTypeDirtyBW = true;
+ fClipStack.restore();
// reserve our layer (if any)
DeviceCM* layer = fMCRec->fLayer; // may be null
// now detach it from fMCRec so we can pop(). Gets freed after its drawn
@@ -798,6 +805,8 @@ void SkCanvas::internalRestore() {
}
SkDELETE(layer);
}
+
+ SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
}
int SkCanvas::getSaveCount() const {
@@ -911,6 +920,8 @@ void SkCanvas::resetMatrix() {
//////////////////////////////////////////////////////////////////////////////
bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
+ AutoValidateClip avc(this);
+
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
fLocalBoundsCompareTypeDirtyBW = true;
@@ -924,6 +935,7 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
SkIRect ir;
fMCRec->fMatrix->mapRect(&r, rect);
+ fClipStack.clipDevRect(r, op);
r.round(&ir);
return fMCRec->fRegion->op(ir, op);
} else {
@@ -938,39 +950,84 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
}
}
-bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
- fDeviceCMDirty = true;
- fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
-
- SkPath devPath;
- path.transform(*fMCRec->fMatrix, &devPath);
-
+static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn,
+ const SkPath& devPath, SkRegion::Op op) {
if (SkRegion::kIntersect_Op == op) {
- return fMCRec->fRegion->setPath(devPath, *fMCRec->fRegion);
+ return currRgn->setPath(devPath, *currRgn);
} else {
SkRegion base;
- const SkBitmap& bm = this->getDevice()->accessBitmap(false);
+ const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
base.setRect(0, 0, bm.width(), bm.height());
if (SkRegion::kReplace_Op == op) {
- return fMCRec->fRegion->setPath(devPath, base);
+ return currRgn->setPath(devPath, base);
} else {
SkRegion rgn;
rgn.setPath(devPath, base);
- return fMCRec->fRegion->op(rgn, op);
+ return currRgn->op(rgn, op);
}
}
}
+bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
+ AutoValidateClip avc(this);
+
+ fDeviceCMDirty = true;
+ fLocalBoundsCompareTypeDirty = true;
+ fLocalBoundsCompareTypeDirtyBW = true;
+
+ SkPath devPath;
+ path.transform(*fMCRec->fMatrix, &devPath);
+
+ // if we called path.swap() we could avoid a deep copy of this path
+ fClipStack.clipDevPath(devPath, op);
+
+ return clipPathHelper(this, fMCRec->fRegion, devPath, op);
+}
+
bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
+ AutoValidateClip avc(this);
+
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
fLocalBoundsCompareTypeDirtyBW = true;
+ // todo: signal fClipStack that we have a region, and therefore (I guess)
+ // we have to ignore it, and use the region directly?
+ fClipStack.clipDevRect(rgn.getBounds());
+
return fMCRec->fRegion->op(rgn, op);
}
+#ifdef SK_DEBUG
+void SkCanvas::validateClip() const {
+ // construct clipRgn from the clipstack
+ const SkDevice* device = this->getDevice();
+ SkIRect ir;
+ ir.set(0, 0, device->width(), device->height());
+ SkRegion clipRgn(ir);
+
+ SkClipStack::B2FIter iter(fClipStack);
+ const SkClipStack::B2FIter::Clip* clip;
+ while ((clip = iter.next()) != NULL) {
+ if (clip->fPath) {
+ clipPathHelper(this, &clipRgn, *clip->fPath, clip->fOp);
+ } else if (clip->fRect) {
+ clip->fRect->round(&ir);
+ clipRgn.op(ir, clip->fOp);
+ } else {
+ break;
+ }
+ }
+
+ // now compare against the current rgn
+ const SkRegion& rgn = this->getTotalClip();
+ SkASSERT(rgn == clipRgn);
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
SkRect r;
SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
new file mode 100644
index 0000000..2b63aea
--- /dev/null
+++ b/src/core/SkClipStack.cpp
@@ -0,0 +1,144 @@
+#include "SkClipStack.h"
+#include "SkPath.h"
+#include <new>
+
+struct SkClipStack::Rec {
+ enum State {
+ kEmpty_State,
+ kRect_State,
+ kPath_State
+ };
+
+ SkPath fPath;
+ SkRect fRect;
+ int fSaveCount;
+ SkRegion::Op fOp;
+ State fState;
+
+ Rec(int saveCount, const SkRect& rect, SkRegion::Op op) : fRect(rect) {
+ fSaveCount = saveCount;
+ fOp = op;
+ fState = kRect_State;
+ }
+
+ Rec(int saveCount, const SkPath& path, SkRegion::Op op) : fPath(path) {
+ fSaveCount = saveCount;
+ fOp = op;
+ fState = kPath_State;
+ }
+
+ /**
+ * Returns true if this Rec can be intersected in place with a new clip
+ */
+ bool canBeIntersected(int saveCount, SkRegion::Op op) const {
+ if (kEmpty_State == fState) {
+ return true;
+ }
+ return fSaveCount == saveCount &&
+ SkRegion::kIntersect_Op == fOp &&
+ SkRegion::kIntersect_Op == op;
+ }
+};
+
+SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
+ fSaveCount = 0;
+}
+
+void SkClipStack::reset() {
+ // don't have a reset() on SkDeque, so fake it here
+ fDeque.~SkDeque();
+ new (&fDeque) SkDeque(sizeof(Rec));
+
+ fSaveCount = 0;
+}
+
+void SkClipStack::save() {
+ fSaveCount += 1;
+}
+
+void SkClipStack::restore() {
+ fSaveCount -= 1;
+ while (!fDeque.empty()) {
+ Rec* rec = (Rec*)fDeque.back();
+ if (rec->fSaveCount <= fSaveCount) {
+ break;
+ }
+ rec->~Rec();
+ fDeque.pop_back();
+ }
+}
+
+void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
+ Rec* rec = (Rec*)fDeque.back();
+ if (rec && rec->canBeIntersected(fSaveCount, op)) {
+ switch (rec->fState) {
+ case Rec::kEmpty_State:
+ return;
+ case Rec::kRect_State:
+ if (!rec->fRect.intersect(rect)) {
+ rec->fState = Rec::kEmpty_State;
+ }
+ return;
+ case Rec::kPath_State:
+ if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
+ rec->fState = Rec::kEmpty_State;
+ return;
+ }
+ break;
+ }
+ }
+ new (fDeque.push_back()) Rec(fSaveCount, rect, op);
+}
+
+void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
+ Rec* rec = (Rec*)fDeque.back();
+ if (rec && rec->canBeIntersected(fSaveCount, op)) {
+ const SkRect& pathBounds = path.getBounds();
+ switch (rec->fState) {
+ case Rec::kEmpty_State:
+ return;
+ case Rec::kRect_State:
+ if (!SkRect::Intersects(rec->fRect, pathBounds)) {
+ rec->fState = Rec::kEmpty_State;
+ return;
+ }
+ break;
+ case Rec::kPath_State:
+ if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
+ rec->fState = Rec::kEmpty_State;
+ return;
+ }
+ break;
+ }
+ }
+ new (fDeque.push_back()) Rec(fSaveCount, path, op);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) : fIter(stack.fDeque) {
+}
+
+const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
+ const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
+ if (NULL == rec) {
+ return NULL;
+ }
+
+ switch (rec->fState) {
+ case SkClipStack::Rec::kEmpty_State:
+ fClip.fRect = NULL;
+ fClip.fPath = NULL;
+ break;
+ case SkClipStack::Rec::kRect_State:
+ fClip.fRect = &rec->fRect;
+ fClip.fPath = NULL;
+ break;
+ case SkClipStack::Rec::kPath_State:
+ fClip.fRect = NULL;
+ fClip.fPath = &rec->fPath;
+ break;
+ }
+ fClip.fOp = rec->fOp;
+ return &fClip;
+}
diff --git a/src/core/SkDeque.cpp b/src/core/SkDeque.cpp
index 4f15051..2c6ce64 100644
--- a/src/core/SkDeque.cpp
+++ b/src/core/SkDeque.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
@@ -25,10 +25,10 @@ struct SkDeque::Head {
char* fBegin; // start of used section in this chunk
char* fEnd; // end of used section in this chunk
char* fStop; // end of the allocated chunk
-
+
char* start() { return (char*)(this + 1); }
const char* start() const { return (const char*)(this + 1); }
-
+
void init(size_t size) {
fNext = fPrev = NULL;
fBegin = fEnd = NULL;
@@ -44,7 +44,7 @@ SkDeque::SkDeque(size_t elemSize)
SkDeque::SkDeque(size_t elemSize, void* storage, size_t storageSize)
: fElemSize(elemSize), fInitialStorage(storage), fCount(0) {
SkASSERT(storageSize == 0 || storage != NULL);
-
+
if (storageSize >= sizeof(Head) + elemSize) {
fFront = (Head*)storage;
fFront->init(storageSize);
@@ -69,7 +69,7 @@ SkDeque::~SkDeque() {
const void* SkDeque::front() const {
Head* front = fFront;
-
+
if (NULL == front) {
return NULL;
}
@@ -108,7 +108,7 @@ void* SkDeque::push_front() {
fFront->init(sizeof(Head) + INIT_ELEM_COUNT * fElemSize);
fBack = fFront; // update our linklist
}
-
+
Head* first = fFront;
char* begin;
@@ -144,7 +144,7 @@ void* SkDeque::push_back() {
fBack->init(sizeof(Head) + INIT_ELEM_COUNT * fElemSize);
fFront = fBack; // update our linklist
}
-
+
Head* last = fBack;
char* end;
@@ -178,7 +178,7 @@ void SkDeque::pop_front() {
Head* first = fFront;
SkASSERT(first != NULL);
-
+
if (first->fBegin == NULL) { // we were marked empty from before
first = first->fNext;
first->fPrev = NULL;
@@ -202,9 +202,9 @@ void SkDeque::pop_back() {
fCount -= 1;
Head* last = fBack;
-
+
SkASSERT(last != NULL);
-
+
if (last->fEnd == NULL) { // we were marked empty from before
last = last->fPrev;
last->fNext = NULL;
@@ -212,7 +212,7 @@ void SkDeque::pop_back() {
fBack = last;
SkASSERT(last != NULL); // else we popped too far
}
-
+
char* end = last->fEnd - fElemSize;
SkASSERT(end >= last->fBegin);
@@ -225,7 +225,7 @@ void SkDeque::pop_back() {
///////////////////////////////////////////////////////////////////////////////
-SkDeque::Iter::Iter(const SkDeque& d) : fElemSize(d.fElemSize) {
+SkDeque::F2BIter::F2BIter(const SkDeque& d) : fElemSize(d.fElemSize) {
fHead = d.fFront;
while (fHead != NULL && fHead->fBegin == NULL) {
fHead = fHead->fNext;
@@ -233,9 +233,9 @@ SkDeque::Iter::Iter(const SkDeque& d) : fElemSize(d.fElemSize) {
fPos = fHead ? fHead->fBegin : NULL;
}
-void* SkDeque::Iter::next() {
+void* SkDeque::F2BIter::next() {
char* pos = fPos;
-
+
if (pos) { // if we were valid, try to move to the next setting
char* next = pos + fElemSize;
SkASSERT(next <= fHead->fEnd);
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index a270677..2921be0 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -11,7 +11,7 @@ SkDevice::SkDevice(SkCanvas* canvas, const SkBitmap& bitmap, bool isForLayer)
// auto-allocate if we're for offscreen drawing
if (isForLayer) {
if (NULL == fBitmap.getPixels() && NULL == fBitmap.pixelRef()) {
- fBitmap.allocPixels();
+ fBitmap.allocPixels();
if (!fBitmap.isOpaque()) {
fBitmap.eraseColor(0);
}
@@ -43,7 +43,7 @@ void SkDevice::getBounds(SkIRect* bounds) const {
bool SkDevice::intersects(const SkIRect& r, SkIRect* sect) const {
SkIRect bounds;
-
+
this->getBounds(&bounds);
return sect ? sect->intersect(r, bounds) : SkIRect::Intersects(r, bounds);
}
@@ -54,7 +54,8 @@ void SkDevice::eraseColor(SkColor eraseColor) {
void SkDevice::onAccessBitmap(SkBitmap* bitmap) {}
-void SkDevice::setMatrixClip(const SkMatrix&, const SkRegion&) {}
+void SkDevice::setMatrixClip(const SkMatrix&, const SkRegion&,
+ const SkClipStack&) {}
///////////////////////////////////////////////////////////////////////////////
@@ -116,7 +117,7 @@ void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
const SkMatrix& matrix, const SkPaint& paint) {
SkBitmap tmp; // storage if we need a subset of bitmap
const SkBitmap* bitmapPtr = &bitmap;
-
+
if (srcRect) {
if (!bitmap.extractSubset(&tmp, *srcRect)) {
return; // extraction failed
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index f98969c..697917a 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -383,7 +383,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
SkGlyph tmpGlyph;
if (fMaskFilter) { // restore the prefilter bounds
- tmpGlyph.fID = origGlyph.fID;
+ tmpGlyph.init(origGlyph.fID);
// need the original bounds, sans our maskfilter
SkMaskFilter* mf = fMaskFilter;
diff --git a/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp
index a657780..901a4d3 100644
--- a/src/effects/SkBlurDrawLooper.cpp
+++ b/src/effects/SkBlurDrawLooper.cpp
@@ -3,6 +3,7 @@
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkMaskFilter.h"
+#include "SkColorFilter.h"
SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
SkColor color, uint32_t flags)
@@ -15,12 +16,28 @@ SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
SkBlurMaskFilter::kNone_BlurFlag;
+ blurFlags |= flags & kHighQuality_BlurFlag ?
+ SkBlurMaskFilter::kHighQuality_BlurFlag :
+ SkBlurMaskFilter::kNone_BlurFlag;
+
fBlur = SkBlurMaskFilter::Create(radius,
- SkBlurMaskFilter::kNormal_BlurStyle,
+ SkBlurMaskFilter::kNormal_BlurStyle,
blurFlags);
}
else
+ {
fBlur = NULL;
+ }
+
+ if (flags & kOverrideColor_BlurFlag)
+ {
+ //The SrcIn xfer mode will multiply 'color' by the incoming alpha
+ fColorFilter = SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcIn_Mode);
+ }
+ else
+ {
+ fColorFilter = NULL;
+ }
}
SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
@@ -29,12 +46,14 @@ SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
fDy = buffer.readScalar();
fBlurColor = buffer.readU32();
fBlur = static_cast<SkMaskFilter*>(buffer.readFlattenable());
+ fColorFilter = static_cast<SkColorFilter*>(buffer.readFlattenable());
fBlurFlags = buffer.readU32() & kAll_BlurFlag;
}
SkBlurDrawLooper::~SkBlurDrawLooper()
{
SkSafeUnref(fBlur);
+ SkSafeUnref(fColorFilter);
}
void SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer)
@@ -43,6 +62,7 @@ void SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer)
buffer.writeScalar(fDy);
buffer.write32(fBlurColor);
buffer.writeFlattenable(fBlur);
+ buffer.writeFlattenable(fColorFilter);
buffer.write32(fBlurFlags);
}
@@ -74,6 +94,7 @@ bool SkBlurDrawLooper::next()
}
fPaint->setColor(blurColor);
fPaint->setMaskFilter(fBlur);
+ fPaint->setColorFilter(fColorFilter);
fCanvas->save(SkCanvas::kMatrix_SaveFlag);
if (fBlurFlags & kIgnoreTransform_BlurFlag)
{
@@ -90,6 +111,7 @@ bool SkBlurDrawLooper::next()
case kAfterEdge:
fPaint->setColor(fSavedColor);
fPaint->setMaskFilter(NULL);
+ fPaint->setColorFilter(NULL);
fCanvas->restore(); // to remove the translate we did earlier
fState = kDone;
return true;
@@ -105,6 +127,7 @@ void SkBlurDrawLooper::restore()
{
fPaint->setColor(fSavedColor);
fPaint->setMaskFilter(NULL);
+ fPaint->setColorFilter(NULL);
fCanvas->restore(); // to remove the translate we did earlier
fState = kDone;
}
diff --git a/src/effects/SkBlurMask.cpp b/src/effects/SkBlurMask.cpp
index a6492c3..f57a177 100644
--- a/src/effects/SkBlurMask.cpp
+++ b/src/effects/SkBlurMask.cpp
@@ -246,13 +246,20 @@ void SkMask_FreeImage(uint8_t* image)
}
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
- SkScalar radius, Style style)
+ SkScalar radius, Style style, Quality quality)
{
if (src.fFormat != SkMask::kA8_Format)
return false;
- int rx = SkScalarCeil(radius);
- int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - radius) * 255);
+ // Force high quality off for small radii (performance)
+ if (radius < SkIntToScalar(3)) quality = kLow_Quality;
+
+ // highQuality: use three box blur passes as a cheap way to approximate a Gaussian blur
+ int passCount = (quality == kHigh_Quality) ? 3 : 1;
+ SkScalar passRadius = SkScalarDiv(radius, SkScalarSqrt(SkIntToScalar(passCount)));
+
+ int rx = SkScalarCeil(passRadius);
+ int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255);
SkASSERT(rx >= 0);
SkASSERT((unsigned)outer_weight <= 255);
@@ -262,8 +269,10 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
int ry = rx; // only do square blur for now
- dst->fBounds.set(src.fBounds.fLeft - rx, src.fBounds.fTop - ry,
- src.fBounds.fRight + rx, src.fBounds.fBottom + ry);
+ int padx = passCount * rx;
+ int pady = passCount * ry;
+ dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
+ src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
dst->fRowBytes = dst->fBounds.width();
dst->fFormat = SkMask::kA8_Format;
dst->fImage = NULL;
@@ -283,15 +292,38 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
// build the blurry destination
{
- SkAutoTMalloc<uint32_t> storage((sw + 1) * (sh + 1));
+ SkAutoTMalloc<uint32_t> storage((sw + 2 * (passCount - 1) * rx + 1) * (sh + 2 * (passCount - 1) * ry + 1));
uint32_t* sumBuffer = storage.get();
+ //pass1: sp is source, dp is destination
build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes);
dump_sum_buffer(sumBuffer, sw, sh);
if (outer_weight == 255)
apply_kernel(dp, rx, ry, sumBuffer, sw, sh);
else
apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight);
+
+ if (quality == kHigh_Quality)
+ {
+ //pass2: dp is source, tmpBuffer is destination
+ int tmp_sw = sw + 2 * rx;
+ int tmp_sh = sh + 2 * ry;
+ SkAutoTMalloc<uint8_t> tmpBuffer(dstSize);
+ build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, dp, tmp_sw);
+ if (outer_weight == 255)
+ apply_kernel(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh);
+ else
+ apply_kernel_interp(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh, outer_weight);
+
+ //pass3: tmpBuffer is source, dp is destination
+ tmp_sw += 2 * rx;
+ tmp_sh += 2 * ry;
+ build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, tmpBuffer.get(), tmp_sw);
+ if (outer_weight == 255)
+ apply_kernel(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh);
+ else
+ apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh, outer_weight);
+ }
}
dst->fImage = dp;
@@ -306,11 +338,11 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
dst->fImage = SkMask::AllocImage(srcSize);
merge_src_with_blur(dst->fImage, src.fRowBytes,
sp, src.fRowBytes,
- dp + rx + ry*dst->fRowBytes, dst->fRowBytes,
+ dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes,
sw, sh);
SkMask::FreeImage(dp);
} else if (style != kNormal_Style) {
- clamp_with_orig(dp + rx + ry*dst->fRowBytes, dst->fRowBytes,
+ clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes,
sp, src.fRowBytes, sw, sh,
style);
}
diff --git a/src/effects/SkBlurMask.h b/src/effects/SkBlurMask.h
index 8f61d54..560ef48 100644
--- a/src/effects/SkBlurMask.h
+++ b/src/effects/SkBlurMask.h
@@ -31,7 +31,12 @@ public:
kStyleCount
};
- static bool Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style);
+ enum Quality {
+ kLow_Quality, //!< box blur
+ kHigh_Quality //!< three pass box blur (similar to gaussian)
+ };
+
+ static bool Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style, Quality quality);
};
#endif
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 8941cd1..41e04b8 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -96,8 +96,10 @@ bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, const SkMa
// a request like 10,000)
static const SkScalar MAX_RADIUS = SkIntToScalar(128);
radius = SkMinScalar(radius, MAX_RADIUS);
+ SkBlurMask::Quality blurQuality = (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
+ SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
- if (SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle))
+ if (SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle, blurQuality))
{
if (margin) {
// we need to integralize radius for our margin, so take the ceil
diff --git a/src/effects/SkEmbossMaskFilter.cpp b/src/effects/SkEmbossMaskFilter.cpp
index 67c8024..9d585ff 100644
--- a/src/effects/SkEmbossMaskFilter.cpp
+++ b/src/effects/SkEmbossMaskFilter.cpp
@@ -73,7 +73,7 @@ bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatr
{
SkScalar radius = matrix.mapRadius(fBlurRadius);
- if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style))
+ if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style, SkBlurMask::kLow_Quality))
return false;
dst->fFormat = SkMask::k3D_Format;
diff --git a/src/effects/SkLayerRasterizer.cpp b/src/effects/SkLayerRasterizer.cpp
index 168fbe9..851f418 100644
--- a/src/effects/SkLayerRasterizer.cpp
+++ b/src/effects/SkLayerRasterizer.cpp
@@ -37,7 +37,7 @@ SkLayerRasterizer::SkLayerRasterizer() : fLayers(sizeof(SkLayerRasterizer_Rec))
SkLayerRasterizer::~SkLayerRasterizer()
{
- SkDeque::Iter iter(fLayers);
+ SkDeque::F2BIter iter(fLayers);
SkLayerRasterizer_Rec* rec;
while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL)
@@ -55,7 +55,7 @@ void SkLayerRasterizer::addLayer(const SkPaint& paint, SkScalar dx, SkScalar dy)
static bool compute_bounds(const SkDeque& layers, const SkPath& path, const SkMatrix& matrix,
const SkIRect* clipBounds, SkIRect* bounds)
{
- SkDeque::Iter iter(layers);
+ SkDeque::F2BIter iter(layers);
SkLayerRasterizer_Rec* rec;
bounds->set(SK_MaxS32, SK_MaxS32, SK_MinS32, SK_MinS32);
@@ -139,7 +139,7 @@ bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
// we set the matrixproc in the loop, as the matrix changes each time (potentially)
draw.fBounder = NULL;
- SkDeque::Iter iter(fLayers);
+ SkDeque::F2BIter iter(fLayers);
SkLayerRasterizer_Rec* rec;
while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) {
@@ -219,7 +219,7 @@ void SkLayerRasterizer::flatten(SkFlattenableWriteBuffer& buffer)
buffer.write32(fLayers.count());
- SkDeque::Iter iter(fLayers);
+ SkDeque::F2BIter iter(fLayers);
const SkLayerRasterizer_Rec* rec;
while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != NULL)
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index a216708..043f0df 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -522,7 +522,7 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
InitFreetype();
FT_Done_FreeType(gFTLibrary);
}
-
+
if (!gLCDSupport && rec->isLCD()) {
// If the runtime Freetype library doesn't support LCD mode, we disable
// it here.
@@ -1261,11 +1261,12 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
/* Export this so that other parts of our FonttHost port can make use of our
ability to extract the name+style from a stream, using FreeType's api.
*/
-bool find_name_and_style(SkStream* stream, SkString* name, SkTypeface::Style* style) {
+SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
+ bool* isFixedWidth) {
FT_Library library;
if (FT_Init_FreeType(&library)) {
- name->set(NULL);
- return false;
+ name->reset();
+ return SkTypeface::kNormal;
}
FT_Open_Args args;
@@ -1292,22 +1293,24 @@ bool find_name_and_style(SkStream* stream, SkString* name, SkTypeface::Style* st
FT_Face face;
if (FT_Open_Face(library, &args, 0, &face)) {
FT_Done_FreeType(library);
- name->set(NULL);
- return false;
+ name->reset();
+ return SkTypeface::kNormal;
}
name->set(face->family_name);
- int tempStyle = SkTypeface::kNormal;
+ int style = SkTypeface::kNormal;
if (face->style_flags & FT_STYLE_FLAG_BOLD) {
- tempStyle |= SkTypeface::kBold;
+ style |= SkTypeface::kBold;
}
if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
- tempStyle |= SkTypeface::kItalic;
+ style |= SkTypeface::kItalic;
+ }
+ if (isFixedWidth) {
+ *isFixedWidth = FT_IS_FIXED_WIDTH(face);
}
- *style = (SkTypeface::Style)tempStyle;
FT_Done_Face(face);
FT_Done_FreeType(library);
- return true;
+ return (SkTypeface::Style)style;
}
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index 7e515d0..d01577d 100644
--- a/src/ports/SkFontHost_android.cpp
+++ b/src/ports/SkFontHost_android.cpp
@@ -31,7 +31,8 @@
#define SK_FONT_FILE_PREFIX "/fonts/"
#endif
-bool find_name_and_style(SkStream* stream, SkString* name, SkTypeface::Style* style);
+SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
+ bool* isFixedWidth);
static void GetFullPathForSysFonts(SkString* full, const char name[]) {
full->set(getenv("ANDROID_ROOT"));
@@ -235,8 +236,9 @@ static void remove_from_names(FamilyRec* emptyFamily)
class FamilyTypeface : public SkTypeface {
public:
- FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember)
- : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) {
+ FamilyTypeface(Style style, bool sysFont, SkTypeface* familyMember,
+ bool isFixedWidth)
+ : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
fIsSysFont = sysFont;
SkAutoMutexAcquire ac(gFamilyMutex);
@@ -280,8 +282,8 @@ private:
class StreamTypeface : public FamilyTypeface {
public:
StreamTypeface(Style style, bool sysFont, SkTypeface* familyMember,
- SkStream* stream)
- : INHERITED(style, sysFont, familyMember) {
+ SkStream* stream, bool isFixedWidth)
+ : INHERITED(style, sysFont, familyMember, isFixedWidth) {
SkASSERT(stream);
stream->ref();
fStream = stream;
@@ -311,8 +313,8 @@ private:
class FileTypeface : public FamilyTypeface {
public:
FileTypeface(Style style, bool sysFont, SkTypeface* familyMember,
- const char path[])
- : INHERITED(style, sysFont, familyMember) {
+ const char path[], bool isFixedWidth)
+ : INHERITED(style, sysFont, familyMember, isFixedWidth) {
SkString fullpath;
if (sysFont) {
@@ -359,18 +361,21 @@ private:
///////////////////////////////////////////////////////////////////////////////
static bool get_name_and_style(const char path[], SkString* name,
- SkTypeface::Style* style, bool isExpected) {
+ SkTypeface::Style* style,
+ bool* isFixedWidth, bool isExpected) {
SkString fullpath;
GetFullPathForSysFonts(&fullpath, path);
SkMMAPStream stream(fullpath.c_str());
if (stream.getLength() > 0) {
- return find_name_and_style(&stream, name, style);
+ *style = find_name_and_attributes(&stream, name, isFixedWidth);
+ return true;
}
else {
SkFILEStream stream(fullpath.c_str());
if (stream.getLength() > 0) {
- return find_name_and_style(&stream, name, style);
+ *style = find_name_and_attributes(&stream, name, isFixedWidth);
+ return true;
}
}
@@ -461,12 +466,14 @@ static void load_system_fonts() {
firstInFamily = NULL;
}
+ bool isFixedWidth;
SkString name;
SkTypeface::Style style;
// we expect all the fonts, except the "fallback" fonts
bool isExpected = (rec[i].fNames != gFBNames);
- if (!get_name_and_style(rec[i].fFileName, &name, &style, isExpected)) {
+ if (!get_name_and_style(rec[i].fFileName, &name, &style,
+ &isFixedWidth, isExpected)) {
continue;
}
@@ -474,7 +481,8 @@ static void load_system_fonts() {
(style,
true, // system-font (cannot delete)
firstInFamily, // what family to join
- rec[i].fFileName) // filename
+ rec[i].fFileName,
+ isFixedWidth) // filename
);
if (rec[i].fNames != NULL) {
@@ -648,11 +656,12 @@ SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
return NULL;
}
+ bool isFixedWidth;
SkString name;
- SkTypeface::Style style;
+ SkTypeface::Style style = find_name_and_attributes(stream, &name, &isFixedWidth);
- if (find_name_and_style(stream, &name, &style)) {
- return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
+ if (!name.isEmpty()) {
+ return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
} else {
return NULL;
}
diff --git a/src/ports/SkFontHost_linux.cpp b/src/ports/SkFontHost_linux.cpp
index e85dff4..9aabce7 100644
--- a/src/ports/SkFontHost_linux.cpp
+++ b/src/ports/SkFontHost_linux.cpp
@@ -32,7 +32,8 @@
#define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/msttcorefonts/"
#endif
-SkTypeface::Style find_name_and_style(SkStream* stream, SkString* name);
+SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
+ bool* isFixedWidth);
static void GetFullPathForSysFonts(SkString* full, const char name[])
{
@@ -237,8 +238,8 @@ static void remove_from_names(FamilyRec* emptyFamily) {
class FamilyTypeface : public SkTypeface {
public:
- FamilyTypeface(Style style, bool sysFont, FamilyRec* family)
- : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1) {
+ FamilyTypeface(Style style, bool sysFont, FamilyRec* family, bool isFixedWidth)
+ : SkTypeface(style, sk_atomic_inc(&gUniqueFontID) + 1, isFixedWidth) {
fIsSysFont = sysFont;
SkAutoMutexAcquire ac(gFamilyMutex);
@@ -283,7 +284,7 @@ private:
*/
class EmptyTypeface : public FamilyTypeface {
public:
- EmptyTypeface() : INHERITED(SkTypeface::kNormal, true, NULL) {}
+ EmptyTypeface() : INHERITED(SkTypeface::kNormal, true, NULL, false) {}
// overrides
virtual SkStream* openStream() { return NULL; }
@@ -296,8 +297,8 @@ private:
class StreamTypeface : public FamilyTypeface {
public:
StreamTypeface(Style style, bool sysFont, FamilyRec* family,
- SkStream* stream)
- : INHERITED(style, sysFont, family) {
+ SkStream* stream, bool isFixedWidth)
+ : INHERITED(style, sysFont, family, isFixedWidth) {
stream->ref();
fStream = stream;
}
@@ -323,8 +324,8 @@ private:
class FileTypeface : public FamilyTypeface {
public:
FileTypeface(Style style, bool sysFont, FamilyRec* family,
- const char path[])
- : INHERITED(style, sysFont, family) {
+ const char path[], bool isFixedWidth)
+ : INHERITED(style, sysFont, family, isFixedWidth) {
fPath.set(path);
}
@@ -364,16 +365,16 @@ private:
///////////////////////////////////////////////////////////////////////////////
static bool get_name_and_style(const char path[], SkString* name,
- SkTypeface::Style* style) {
+ SkTypeface::Style* style, bool* isFixedWidth) {
SkMMAPStream stream(path);
if (stream.getLength() > 0) {
- *style = find_name_and_style(&stream, name);
+ *style = find_name_and_attributes(&stream, name, isFixedWidth);
return true;
}
else {
SkFILEStream stream(path);
if (stream.getLength() > 0) {
- *style = find_name_and_style(&stream, name);
+ *style = find_name_and_attributes(&stream, name, isFixedWidth);
return true;
}
}
@@ -402,10 +403,11 @@ static void load_system_fonts() {
SkString filename;
GetFullPathForSysFonts(&filename, name.c_str());
+ bool isFixedWidth;
SkString realname;
SkTypeface::Style style = SkTypeface::kNormal; // avoid uninitialized warning
- if (!get_name_and_style(filename.c_str(), &realname, &style)) {
+ if (!get_name_and_style(filename.c_str(), &realname, &style, &isFixedWidth)) {
SkDebugf("------ can't load <%s> as a font\n", filename.c_str());
continue;
}
@@ -424,7 +426,8 @@ static void load_system_fonts() {
(style,
true, // system-font (cannot delete)
family, // what family to join
- filename.c_str()) // filename
+ filename.c_str(),
+ isFixedWidth) // filename
);
if (NULL == family) {
@@ -586,11 +589,12 @@ SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
SkDELETE(stream);
return NULL;
}
-
+
+ bool isFixedWidth;
SkString name;
- SkTypeface::Style style = find_name_and_style(stream, &name);
+ SkTypeface::Style style = find_name_and_attributes(stream, &name, &isFixedWidth);
- return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream));
+ return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth));
}
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp
index c2e43fa..c2055aa 100644
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -22,10 +22,12 @@
#include "SkAdvancedTypefaceMetrics.h"
#include "SkStream.h"
#include "SkThread.h"
+#include "SkUtils.h"
#ifdef WIN32
#include "windows.h"
#include "tchar.h"
+#include "Usp10.h"
// client3d has to undefine this for now
#define CAN_USE_LOGFONT_NAME
@@ -179,14 +181,16 @@ protected:
virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
//virtual SkDeviceContext getDC() {return ddc;}
private:
- LOGFONT lf;
- MAT2 mat22;
- HDC ddc;
- HFONT savefont;
- HFONT font;
+ LOGFONT lf;
+ MAT2 mat22;
+ HDC ddc;
+ HFONT savefont;
+ HFONT font;
+ SCRIPT_CACHE sc;
};
-SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) : SkScalerContext(desc), ddc(0), font(0), savefont(0) {
+SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
+ : SkScalerContext(desc), ddc(0), font(0), savefont(0), sc(0) {
SkAutoMutexAcquire ac(gFTMutex);
lf = LogFontTypeface::FindById(fRec.fFontID)->logFont();
@@ -216,6 +220,9 @@ SkScalerContext_Windows::~SkScalerContext_Windows() {
if (font) {
::DeleteObject(font);
}
+ if (sc) {
+ ::ScriptFreeCache(&sc);
+ }
}
unsigned SkScalerContext_Windows::generateGlyphCount() const {
@@ -225,9 +232,26 @@ unsigned SkScalerContext_Windows::generateGlyphCount() const {
uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
uint16_t index = 0;
- // TODO(ctguil): Support values larger than 16bits.
- WCHAR c = SkToU16(uni);
- GetGlyphIndicesW(ddc, &c, 1, &index, 0);
+ WCHAR c[2];
+ // TODO(ctguil): Support characters that generate more than one glyph.
+ if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) {
+ // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
+ SkAssertResult(GetGlyphIndicesW(ddc, c, 1, &index, 0));
+ } else {
+ // Use uniscribe to detemine glyph index for non-BMP characters.
+ // Need to add extra item to SCRIPT_ITEM to work around a bug in older
+ // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643
+ SCRIPT_ITEM si[2 + 1];
+ int items;
+ SkAssertResult(
+ SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items)));
+
+ WORD log[2];
+ SCRIPT_VISATTR vsa;
+ int glyphs;
+ SkAssertResult(SUCCEEDED(ScriptShape(
+ ddc, &sc, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
+ }
return index;
}
@@ -524,6 +548,7 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
}
info->fEmSize = otm.otmEMSquare;
info->fMultiMaster = false;
+ info->fLastGlyphID = 0;
info->fStyle = 0;
// If this bit is clear the font is a fixed pitch font.
@@ -578,6 +603,15 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
} else if (perGlyphInfo) {
info->fGlyphWidths.reset(
getAdvanceData(hdc, SHRT_MAX, &getWidthAdvance));
+
+ // Obtain the last glyph index.
+ SkAdvancedTypefaceMetrics::WidthRange* last = info->fGlyphWidths.get();
+ if (last) {
+ while (last->fNext.get()) {
+ last = last->fNext.get();
+ }
+ info->fLastGlyphID = last->fEndId;
+ }
}
Error: