void SkGScalerContext::generateMetrics(SkGlyph* glyph) { fProxy->getMetrics(glyph); SkVector advance; fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), SkFloatToScalar(glyph->fAdvanceY), &advance); glyph->fAdvanceX = SkScalarToFloat(advance.fX); glyph->fAdvanceY = SkScalarToFloat(advance.fY); SkPath path; fProxy->getPath(*glyph, &path); path.transform(fMatrix); SkRect storage; const SkPaint& paint = fFace->paint(); const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), &storage, SkPaint::kFill_Style); SkIRect ibounds; newBounds.roundOut(&ibounds); glyph->fLeft = ibounds.fLeft; glyph->fTop = ibounds.fTop; glyph->fWidth = ibounds.width(); glyph->fHeight = ibounds.height(); glyph->fMaskFormat = SkMask::kARGB32_Format; }
static bool oval_contains(const SkRect& r, SkScalar x, SkScalar y) { SkMatrix m; m.setRectToRect(r, gUnitSquare, SkMatrix::kFill_ScaleToFit); SkPoint pt; m.mapXY(x, y, &pt); return pt.lengthSqd() <= 1; }
SkPoint invertPt(SkScalar x, SkScalar y) { SkPoint pt; SkMatrix m; fMatrix.invert(&m); m.mapXY(x, y, &pt); return pt; }
void SkGScalerContext::generateAdvance(SkGlyph* glyph) { fProxy->getAdvance(glyph); SkVector advance; fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), SkFloatToScalar(glyph->fAdvanceY), &advance); glyph->fAdvanceX = SkScalarToFloat(advance.fX); glyph->fAdvanceY = SkScalarToFloat(advance.fY); }
void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { SkASSERT(fDDC); GLYPHMETRICS gm; sk_bzero(&gm, sizeof(gm)); glyph->fRsbDelta = 0; glyph->fLsbDelta = 0; // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller // BlackBlox; we need the bigger one in case we need the image. fAdvance is the same. uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); if (GDI_ERROR != ret) { if (ret == 0) { // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly! gm.gmBlackBoxX = gm.gmBlackBoxY = 0; } glyph->fWidth = gm.gmBlackBoxX; glyph->fHeight = gm.gmBlackBoxY; glyph->fTop = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY); glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x); glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY); // we outset by 1 in all dimensions, since the lcd image may bleed outside // of the computed bounds returned by GetGlyphOutline. // This was deduced by trial and error for small text (e.g. 8pt), so there // maybe a more precise way to make this adjustment... if (SkMask::kLCD16_Format == fRec.fMaskFormat) { glyph->fWidth += 2; glyph->fHeight += 2; glyph->fTop -= 1; glyph->fLeft -= 1; } if (fHiResFont) { SelectObject(fDDC, fHiResFont); sk_bzero(&gm, sizeof(gm)); ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity); if (GDI_ERROR != ret) { SkPoint advance; fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance); glyph->fAdvanceX = SkScalarToFixed(advance.fX); glyph->fAdvanceY = SkScalarToFixed(advance.fY); } SelectObject(fDDC, fFont); } } else { glyph->fWidth = 0; } }
bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const { if (local) { SkMatrix m; this->localToGlobal(&m); if (!m.invert(&m)) { return false; } SkPoint p; m.mapXY(x, y, &p); local->set(p.fX, p.fY); } return true; }
void SkRandomScalerContext::generateMetrics(SkGlyph* glyph) { fProxy->getAdvance(glyph); SkVector advance; fMatrix.mapXY(SkFixedToScalar(glyph->fAdvanceX), SkFixedToScalar(glyph->fAdvanceY), &advance); glyph->fAdvanceX = SkScalarToFixed(advance.fX); glyph->fAdvanceY = SkScalarToFixed(advance.fY); SkPath path; fProxy->getPath(*glyph, &path); path.transform(fMatrix); SkRect storage; const SkPaint& paint = fFace->paint(); const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(), &storage, SkPaint::kFill_Style); SkIRect ibounds; newBounds.roundOut(&ibounds); glyph->fLeft = ibounds.fLeft; glyph->fTop = ibounds.fTop; glyph->fWidth = ibounds.width(); glyph->fHeight = ibounds.height(); // Here we will change the mask format of the glyph // NOTE this is being overridden by the base class SkMask::Format format; switch (glyph->getGlyphID() % 6) { case 0: format = SkMask::kLCD16_Format; break; case 1: format = SkMask::kA8_Format; break; case 2: format = SkMask::kARGB32_Format; break; default: // we will fiddle with these in generate image format = (SkMask::Format)MASK_FORMAT_UNKNOWN; } glyph->fMaskFormat = format; }
SkMatrix Viewer::computeMatrix() { SkMatrix m; m.reset(); if (fZoomLevel) { SkPoint center; //m = this->getLocalMatrix();//.invert(&m); m.mapXY(fZoomCenterX, fZoomCenterY, ¢er); SkScalar cx = center.fX; SkScalar cy = center.fY; m.setTranslate(-cx, -cy); m.postScale(fZoomScale, fZoomScale); m.postTranslate(cx, cy); } m.preConcat(fGesture.localM()); m.preConcat(fGesture.globalM()); return m; }
void GrBitmapTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y) { SkASSERT(byteLength == 0 || text != NULL); // nothing to draw if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { return; } this->init(rt, clip, paint, skPaint); SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix); SkGlyphCache* cache = autoCache.getCache(); GrFontScaler* fontScaler = GetGrFontScaler(cache); // transform our starting point { SkPoint loc; viewMatrix.mapXY(x, y, &loc); x = loc.fX; y = loc.fY; } // need to measure first int numGlyphs; if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { SkVector stopVector; numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector); SkScalar stopX = stopVector.fX; SkScalar stopY = stopVector.fY; if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { stopX = SkScalarHalf(stopX); stopY = SkScalarHalf(stopY); } x -= stopX; y -= stopY; } else { numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); } fTotalVertexCount = kVerticesPerGlyph*numGlyphs; const char* stop = text + byteLength; SkAutoKern autokern; SkFixed fxMask = ~0; SkFixed fyMask = ~0; SkScalar halfSampleX, halfSampleY; if (cache->isSubpixel()) { halfSampleX = halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound); SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix); if (kX_SkAxisAlignment == baseline) { fyMask = 0; halfSampleY = SK_ScalarHalf; } else if (kY_SkAxisAlignment == baseline) { fxMask = 0; halfSampleX = SK_ScalarHalf; } } else { halfSampleX = halfSampleY = SK_ScalarHalf; } Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX); Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY); // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for // performance reasons we just invert here instead if (!viewMatrix.invert(&fLocalMatrix)) { SkDebugf("Cannot invert viewmatrix\n"); return; } while (text < stop) { const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); fx += autokern.adjust(glyph); if (glyph.fWidth) { this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), glyph.getSubXFixed(), glyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), fontScaler); } fx += glyph.fAdvanceX; fy += glyph.fAdvanceY; } this->finish(); }
void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { SkASSERT(fDDC); if (fType == SkScalerContext_Windows::kBitmap_Type) { SIZE size; WORD glyphs = glyph->getGlyphID(0); if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) { glyph->fWidth = SkToS16(fTM.tmMaxCharWidth); } else { glyph->fWidth = SkToS16(size.cx); } glyph->fHeight = SkToS16(size.cy); glyph->fTop = SkToS16(-fTM.tmAscent); glyph->fLeft = SkToS16(0); glyph->fAdvanceX = SkIntToFixed(glyph->fWidth); glyph->fAdvanceY = 0; //Apply matrix to values. glyph->fAdvanceY = SkFixedMul(SkFIXEDToFixed(fMat22.eM21), glyph->fAdvanceX); glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX); return; } GLYPHMETRICS gm; sk_bzero(&gm, sizeof(gm)); glyph->fRsbDelta = 0; glyph->fLsbDelta = 0; // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller // BlackBlox; we need the bigger one in case we need the image. fAdvance is the same. uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); if (GDI_ERROR == ret) { ensure_typeface_accessible(fRec.fFontID); ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); } if (GDI_ERROR != ret) { if (ret == 0) { // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly! gm.gmBlackBoxX = gm.gmBlackBoxY = 0; } glyph->fWidth = gm.gmBlackBoxX; glyph->fHeight = gm.gmBlackBoxY; glyph->fTop = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY); glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x); glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY); // we outset in all dimensions, since the image may bleed outside // of the computed bounds returned by GetGlyphOutline. // This was deduced by trial and error for small text (e.g. 8pt), so there // maybe a more precise way to make this adjustment... // // This test shows us clipping the tops of some of the CJK fonts unless we // increase the top of the box by 2, hence the height by 4. This seems to // correspond to an embedded bitmap font, but not sure. // LayoutTests/fast/text/backslash-to-yen-sign-euc.html // if (glyph->fWidth) { // don't outset an empty glyph glyph->fWidth += 4; glyph->fHeight += 4; glyph->fTop -= 2; glyph->fLeft -= 2; } if (fHiResFont) { SelectObject(fDDC, fHiResFont); sk_bzero(&gm, sizeof(gm)); ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity); if (GDI_ERROR != ret) { SkPoint advance; fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance); glyph->fAdvanceX = SkScalarToFixed(advance.fX); glyph->fAdvanceY = SkScalarToFixed(advance.fY); } SelectObject(fDDC, fFont); } } else { glyph->zeroMetrics(); } }