static void doDraw(SkCanvas* canvas, SkPaint* paint, const int isrc[], const int idst[], int count) { SkMatrix matrix; SkPoint src[4], dst[4]; for (int i = 0; i < count; i++) { src[i].set(SkIntToScalar(isrc[2*i+0]), SkIntToScalar(isrc[2*i+1])); dst[i].set(SkIntToScalar(idst[2*i+0]), SkIntToScalar(idst[2*i+1])); } canvas->save(); matrix.setPolyToPoly(src, dst, count); canvas->concat(matrix); paint->setColor(SK_ColorGRAY); paint->setStyle(SkPaint::kStroke_Style); const SkScalar D = SkIntToScalar(64); canvas->drawRectCoords(0, 0, D, D, *paint); canvas->drawLine(0, 0, D, D, *paint); canvas->drawLine(0, D, D, 0, *paint); SkPaint::FontMetrics fm; paint->getFontMetrics(&fm); paint->setColor(SK_ColorRED); paint->setStyle(SkPaint::kFill_Style); SkScalar x = D/2; float y = D/2 - (fm.fAscent + fm.fDescent)/2; SkString str; str.appendS32(count); canvas->drawText(str.c_str(), str.size(), x, SkFloatToScalar(y), *paint); canvas->restore(); }
void FontPlatformData::setupPaint(SkPaint* paint) const { if (hashTableDeletedFontValue() == mTypeface) paint->setTypeface(0); else paint->setTypeface(mTypeface); paint->setAntiAlias(true); paint->setSubpixelText(true); paint->setHinting(SkPaint::kSlight_Hinting); paint->setTextSize(SkFloatToScalar(mTextSize)); if (!mForceFakeBold & 0x02) paint->setFakeBoldText(mFakeBold); else paint->setFakeBoldText(mForceFakeBold & 0x01); if (!mForceFakeItalic & 0x02) paint->setTextSkewX(mFakeItalic ? -SK_Scalar1/4 : 0); else paint->setTextSkewX((mForceFakeItalic & 0x01) ? -SK_Scalar1/4 : 0); /*guoxiaolei 20120827 end>*/ #ifndef SUPPORT_COMPLEX_SCRIPTS paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); #endif }
static void setupPaintForFont(SkPaint* paint, GraphicsContext* context, SkTypeface* face, float size, uint32_t textFlags) { paint->setTextSize(SkFloatToScalar(size)); paint->setTypeface(face); if (!context->couldUseLCDRenderedText()) { textFlags &= ~SkPaint::kLCDRenderText_Flag; // If we *just* clear our request for LCD, then GDI seems to // sometimes give us AA text, and sometimes give us BW text. Since the // original intent was LCD, we want to force AA (rather than BW), so we // add a special bit to tell Skia to do its best to avoid the BW: by // drawing LCD offscreen and downsampling that to AA. textFlags |= SkPaint::kGenA8FromLCD_Flag; } static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag | SkPaint::kGenA8FromLCD_Flag; // now copy in just the text flags SkASSERT(!(textFlags & ~textFlagsMask)); uint32_t flags = paint->getFlags(); flags &= ~textFlagsMask; flags |= textFlags; paint->setFlags(flags); }
PassRefPtr<SkImageFilter> FEOffset::createImageFilter(SkiaImageFilterBuilder* builder) { RefPtr<SkImageFilter> input(builder->build(inputEffect(0), operatingColorSpace())); Filter* filter = this->filter(); SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); return adoptRef(SkOffsetImageFilter::Create(SkFloatToScalar(filter->applyHorizontalScale(m_dx)), SkFloatToScalar(filter->applyVerticalScale(m_dy)), input.get(), &cropRect)); }
cairo_t * _cairo_skia_context_create (void *target) { cairo_skia_surface_t *surface = (cairo_skia_surface_t *) target; cairo_skia_context_t *cr; cr = (cairo_skia_context_t *) _freed_pool_get (&context_pool); if (unlikely (cr == NULL)) { cr = new cairo_skia_context_t; if (unlikely (cr == NULL)) return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); cr->path = new SkPath; cr->paint = new SkPaint; } _cairo_init (&cr->base, &_cairo_skia_context_backend); cr->source = NULL; cr->source_image = NULL; cr->paint->setStrokeWidth (SkFloatToScalar (2.0)); cr->target = (cairo_skia_surface_t *) cairo_surface_reference ((cairo_surface_t *) target); cr->original = (cairo_skia_surface_t *) cairo_surface_reference ((cairo_surface_t *) target); cr->canvas = new SkCanvas (*surface->bitmap); cr->canvas->save (); cairo_matrix_init_identity (&cr->matrix); return &cr->base; }
void FontPlatformData::setupPaint(SkPaint* paint) const { const float ts = m_textSize >= 0 ? m_textSize : 12; paint->setAntiAlias(m_style.useAntiAlias == FontRenderStyle::NoPreference ? isSkiaAntiAlias : m_style.useAntiAlias); switch (m_style.useHinting) { case FontRenderStyle::NoPreference: paint->setHinting(skiaHinting); break; case 0: paint->setHinting(SkPaint::kNo_Hinting); break; default: paint->setHinting(static_cast<SkPaint::Hinting>(m_style.hintStyle)); break; } paint->setEmbeddedBitmapText(m_style.useBitmaps); paint->setTextSize(SkFloatToScalar(ts)); paint->setTypeface(m_typeface); paint->setFakeBoldText(m_fakeBold); paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0); paint->setAutohinted(m_style.useAutoHint); paint->setSubpixelText(m_style.useSubpixelPositioning == FontRenderStyle::NoPreference ? useSkiaSubpixelPositioning : m_style.useSubpixelPositioning); if (m_style.useAntiAlias == 1 || (m_style.useAntiAlias == FontRenderStyle::NoPreference && isSkiaAntiAlias)) paint->setLCDRenderText(m_style.useSubpixelRendering == FontRenderStyle::NoPreference ? useSkiaSubpixelRendering : m_style.useSubpixelRendering); }
void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const { paint->setAntiAlias(m_style.useAntiAlias); paint->setHinting(static_cast<SkPaint::Hinting>(m_style.hintStyle)); paint->setEmbeddedBitmapText(m_style.useBitmaps); paint->setAutohinted(m_style.useAutoHint); if (m_style.useAntiAlias) paint->setLCDRenderText(m_style.useSubpixelRendering); // Do not enable subpixel text on low-dpi if full hinting is requested. bool useSubpixelText = paint->getHinting() != SkPaint::kFull_Hinting || (context && context->deviceScaleFactor() > 1.0f); // TestRunner specifically toggles the subpixel positioning flag. if (useSubpixelText) paint->setSubpixelText(true); else paint->setSubpixelText(m_style.useSubpixelPositioning); const float ts = m_textSize >= 0 ? m_textSize : 12; paint->setTextSize(SkFloatToScalar(ts)); paint->setTypeface(m_typeface); paint->setFakeBoldText(m_syntheticBold); paint->setTextSkewX(m_syntheticItalic ? -SK_Scalar1 / 4 : 0); }
static void get_adjusted_radii(SkScalar passRadius, int *loRadius, int *hiRadius) { *loRadius = *hiRadius = SkScalarCeil(passRadius); if (SkIntToScalar(*hiRadius) - passRadius > SkFloatToScalar(0.5f)) { *loRadius = *hiRadius - 1; } }
static SkMaskFilter* createEmboss(JNIEnv* env, jobject, jfloatArray dirArray, float ambient, float specular, float radius) { SkScalar direction[3]; AutoJavaFloatArray autoDir(env, dirArray, 3); float* values = autoDir.ptr(); for (int i = 0; i < 3; i++) { direction[i] = SkFloatToScalar(values[i]); } SkMaskFilter* filter = SkBlurMaskFilter::CreateEmboss(direction, SkFloatToScalar(ambient), SkFloatToScalar(specular), SkFloatToScalar(radius)); ThrowIAE_IfNull(env, filter); return filter; }
sk_sp<SkImageFilter> FEDropShadow::createImageFilter() { sk_sp<SkImageFilter> input( SkiaImageFilterBuilder::build(inputEffect(0), operatingColorSpace())); float dx = getFilter()->applyHorizontalScale(m_dx); float dy = getFilter()->applyVerticalScale(m_dy); float stdX = getFilter()->applyHorizontalScale(m_stdX); float stdY = getFilter()->applyVerticalScale(m_stdY); Color color = adaptColorToOperatingColorSpace( m_shadowColor.combineWithAlpha(m_shadowOpacity)); SkImageFilter::CropRect cropRect = getCropRect(); return SkDropShadowImageFilter::Make( SkFloatToScalar(dx), SkFloatToScalar(dy), SkFloatToScalar(stdX), SkFloatToScalar(stdY), color.rgb(), SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, std::move(input), &cropRect); }
void DrawTargetSkia::StrokeLine(const Point &aStart, const Point &aEnd, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aOptions) { MarkChanged(); AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) { return; } mCanvas->drawLine(SkFloatToScalar(aStart.x), SkFloatToScalar(aStart.y), SkFloatToScalar(aEnd.x), SkFloatToScalar(aEnd.y), paint.mPaint); }
void TextLayout::drawTextOnPath(SkPaint* paint, const Char16* text, Int32 count, Int32 bidiFlags, Float hOffset, Float vOffset, SkPath* path, SkCanvas* canvas) { SkScalar h_ = SkFloatToScalar(hOffset); SkScalar v_ = SkFloatToScalar(vOffset); sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, text, 0, count, count, bidiFlags); if (value == NULL) { return; } // Beware: this needs Glyph encoding (already done on the Paint constructor) canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint); }
bool SkPathContainsPoint(const SkPath& originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRect bounds = originalPath.getBounds(); // We can immediately return false if the point is outside the bounding // rect. We don't use bounds.contains() here, since it would exclude // points on the right and bottom edges of the bounding rect, and we want // to include them. SkScalar fX = SkFloatToScalar(point.x()); SkScalar fY = SkFloatToScalar(point.y()); if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; // Scale the path to a large size before hit testing for two reasons: // 1) Skia has trouble with coordinates close to the max signed 16-bit values, so we scale larger paths down. // TODO: when Skia is patched to work properly with large values, this will not be necessary. // 2) Skia does not support analytic hit testing, so we scale paths up to do raster hit testing with subpixel accuracy. // 3) Scale the x/y axis separately so an extreme large/small scale factor on one axis won't // ruin the resolution of the other axis. SkScalar biggestCoordX = std::max(bounds.fRight, -bounds.fLeft); SkScalar biggestCoordY = std::max(bounds.fBottom, -bounds.fTop); if (SkScalarNearlyZero(biggestCoordX) || SkScalarNearlyZero(biggestCoordY)) return false; biggestCoordX = std::max(biggestCoordX, std::fabs(fX) + 1); biggestCoordY = std::max(biggestCoordY, std::fabs(fY) + 1); const SkScalar kMaxCoordinate = SkIntToScalar(1 << 15); SkScalar scaleX = kMaxCoordinate / biggestCoordX; SkScalar scaleY = kMaxCoordinate / biggestCoordY; SkRegion rgn; SkRegion clip; SkMatrix m; SkPath scaledPath(originalPath); scaledPath.setFillType(ft); m.setScale(scaleX, scaleY); scaledPath.transform(m, 0); int x = static_cast<int>(floorf(0.5f + point.x() * scaleX)); int y = static_cast<int>(floorf(0.5f + point.y() * scaleY)); clip.setRect(x - 1, y - 1, x + 1, y + 1); return rgn.setPath(scaledPath, clip); }
void PlatformGraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) { size_t dashLength = dashes.size(); if (!dashLength) return; size_t count = !(dashLength % 2) ? dashLength : dashLength * 2; SkScalar* intervals = new SkScalar[count]; for (unsigned int i = 0; i < count; i++) intervals[i] = SkFloatToScalar(dashes[i % dashLength]); SkPathEffect **effectPtr = &m_state->pathEffect; SkSafeUnref(*effectPtr); *effectPtr = new SkDashPathEffect(intervals, count, SkFloatToScalar(dashOffset)); delete[] intervals; }
PassRefPtr<SkImageFilter> FEConvolveMatrix::createImageFilter(SkiaImageFilterBuilder* builder) { RefPtr<SkImageFilter> input(builder->build(inputEffect(0), operatingColorSpace())); SkISize kernelSize(SkISize::Make(m_kernelSize.width(), m_kernelSize.height())); int numElements = kernelSize.width() * kernelSize.height(); SkScalar gain = SkFloatToScalar(1.0f / m_divisor); SkScalar bias = SkFloatToScalar(m_bias * 255); SkIPoint target = SkIPoint::Make(m_targetOffset.x(), m_targetOffset.y()); SkMatrixConvolutionImageFilter::TileMode tileMode = toSkiaTileMode(m_edgeMode); bool convolveAlpha = !m_preserveAlpha; OwnPtr<SkScalar[]> kernel = adoptArrayPtr(new SkScalar[numElements]); for (int i = 0; i < numElements; ++i) kernel[i] = SkFloatToScalar(m_kernelMatrix[numElements - 1 - i]); SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset()); return adoptRef(SkMatrixConvolutionImageFilter::Create(kernelSize, kernel.get(), gain, bias, target, tileMode, convolveAlpha, input.get(), &cropRect)); }
static inline float transformAngle(const SkMatrix* matrix, float angleRadians) { // Construct and transform a vector oriented at the specified clockwise angle from vertical. // Coordinate system: down is increasing Y, right is increasing X. SkPoint vector; vector.fX = SkFloatToScalar(sinf(angleRadians)); vector.fY = SkFloatToScalar(-cosf(angleRadians)); matrix->mapVectors(& vector, 1); // Derive the transformed vector's clockwise angle from vertical. float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY)); if (result < - M_PI_2) { result += M_PI; } else if (result > M_PI_2) { result -= M_PI; } return result; }
SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) { SkScalar seconds = SkFloatToScalar(gAnimTime / 1000.0f); SkScalar value = SkScalarMul(speed, seconds); if (period) { value = SkScalarMod(value, period); } return value; }
const SkMatrix& TestMatrix(SkMWCRandom* random) { static SkMatrix gMatrices[5]; static bool gOnce; if (!gOnce) { gMatrices[0].reset(); gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100)); gMatrices[2].setRotate(SkIntToScalar(17)); gMatrices[3].setRotate(SkIntToScalar(185)); gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33)); gMatrices[3].postScale(SkIntToScalar(2), SK_ScalarHalf); gMatrices[4].setRotate(SkIntToScalar(215)); gMatrices[4].set(SkMatrix::kMPersp0, SkFloatToScalar(0.00013f)); gMatrices[4].set(SkMatrix::kMPersp1, SkFloatToScalar(-0.000039f)); gOnce = true; } return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))]; }
static cairo_status_t _cairo_skia_context_set_miter_limit (void *abstract_cr, double limit) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setStrokeMiter (SkFloatToScalar (limit)); return CAIRO_STATUS_SUCCESS; }
void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, FloatPoint const& point, int, int) const { SkCanvas* canvas = gc->platformContext()->mCanvas; SkPaint paint; if (!setupForText(&paint, gc, primaryFont())) { return; } // go to chars, instead of glyphs, which was set by setupForText() paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); canvas->drawText(run.characters(), run.length() << 1, SkFloatToScalar(point.x()), SkFloatToScalar(point.y()), paint); }
SkImageFilter* FEDisplacementMap::createImageFilter(SkiaImageFilterBuilder* builder) { SkImageFilter* color = builder->build(inputEffect(0), operatingColorSpace()); SkImageFilter* displ = builder->build(inputEffect(1), operatingColorSpace()); SkDisplacementMapEffect::ChannelSelectorType typeX = toSkiaMode(m_xChannelSelector); SkDisplacementMapEffect::ChannelSelectorType typeY = toSkiaMode(m_yChannelSelector); return new SkDisplacementMapEffect(typeX, typeY, SkFloatToScalar(m_scale), displ, color); }
virtual void onDraw(SkCanvas* canvas) { this->drawBG(canvas); SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED }; SkScalar pos[] = { 0, SkFloatToScalar(0.01f), SkFloatToScalar(0.99f), SK_Scalar1 }; SkPoint c0; c0.iset(-80, 25); SkScalar r0 = SkIntToScalar(70); SkPoint c1; c1.iset(0, 25); SkScalar r1 = SkIntToScalar(150); SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors, pos, SK_ARRAY_COUNT(pos), SkShader::kClamp_TileMode); SkPaint paint; paint.setShader(s)->unref(); canvas->drawPaint(paint); }
SkMaskFilter* CEmbossMaskFilter::NativeConstructor( /* [in] */ const ArrayOf<Float>& dirArray, /* [in] */ Float ambient, /* [in] */ Float specular, /* [in] */ Float blurRadius) { SkScalar direction[3]; for (Int32 i = 0; i < 3; i++) { direction[i] = SkFloatToScalar(dirArray[i]); } SkMaskFilter* filter = SkBlurMaskFilter::CreateEmboss( direction, SkFloatToScalar(ambient), SkFloatToScalar(specular), SkFloatToScalar(blurRadius)); return filter; }
static void Interpolator_setRepeatMirror(JNIEnv* env, jobject clazz, jlong interpHandle, jfloat repeatCount, jboolean mirror) { SkInterpolator* interp = reinterpret_cast<SkInterpolator*>(interpHandle); if (repeatCount > 32000) repeatCount = 32000; interp->setRepeatCount(SkFloatToScalar(repeatCount)); interp->setMirror(mirror != 0); }
static cairo_status_t _cairo_skia_context_set_line_width (void *abstract_cr, double line_width) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setStrokeWidth (SkFloatToScalar (line_width)); return CAIRO_STATUS_SUCCESS; }
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRect bounds = originalPath->getBounds(); // We can immediately return false if the point is outside the bounding // rect. We don't use bounds.contains() here, since it would exclude // points on the right and bottom edges of the bounding rect, and we want // to include them. SkScalar fX = SkFloatToScalar(point.x()); SkScalar fY = SkFloatToScalar(point.y()); if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; // Scale the path to a large size before hit testing for two reasons: // 1) Skia has trouble with coordinates close to the max signed 16-bit values, so we scale larger paths down. // TODO: when Skia is patched to work properly with large values, this will not be necessary. // 2) Skia does not support analytic hit testing, so we scale paths up to do raster hit testing with subpixel accuracy. SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (SkScalarNearlyZero(biggestCoord)) return false; biggestCoord = std::max(std::max(biggestCoord, fX + 1), fY + 1); const SkScalar kMaxCoordinate = SkIntToScalar(1 << 15); SkScalar scale = SkScalarDiv(kMaxCoordinate, biggestCoord); SkRegion rgn; SkRegion clip; SkMatrix m; SkPath scaledPath; SkPath::FillType originalFillType = originalPath->getFillType(); originalPath->setFillType(ft); m.setScale(scale, scale); originalPath->transform(m, &scaledPath); int x = static_cast<int>(floorf(0.5f + point.x() * scale)); int y = static_cast<int>(floorf(0.5f + point.y() * scale)); clip.setRect(x - 1, y - 1, x + 1, y + 1); bool contains = rgn.setPath(scaledPath, clip); originalPath->setFillType(originalFillType); return contains; }
void PlatformContextSkia::beginLayerClippedToImage(const FloatRect& rect, const ImageBuffer* imageBuffer) { SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), SkFloatToScalar(rect.maxX()), SkFloatToScalar(rect.maxY()) }; if (imageBuffer->internalSize().isEmpty()) { m_canvas->clipRect(bounds); return; } // Skia doesn't support clipping to an image, so we create a layer. The next // time restore is invoked the layer and |imageBuffer| are combined to // create the resulting image. m_state->m_clip = bounds; // Get the absolute coordinates of the stored clipping rectangle to make it // independent of any transform changes. canvas()->getTotalMatrix().mapRect(&m_state->m_clip); SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag); saveLayer(&bounds, 0, saveFlags); const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap(); if (m_trackOpaqueRegion) { SkRect opaqueRect = bitmap->isOpaque() ? m_state->m_clip : SkRect::MakeEmpty(); m_opaqueRegion.setImageMask(opaqueRect); } // Copy off the image as |imageBuffer| may be deleted before restore is invoked. if (!bitmap->pixelRef()) { // The bitmap owns it's pixels. This happens when we've allocated the // pixels in some way and assigned them directly to the bitmap (as // happens when we allocate a DIB). In this case the assignment operator // does not copy the pixels, rather the copied bitmap ends up // referencing the same pixels. As the pixels may not live as long as we // need it to, we copy the image. bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config); } else { // If there is a pixel ref, we can safely use the assignment operator. m_state->m_imageBufferClip = *bitmap; } }
static SkPoint* SetCurve(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, SkPoint crv[4]) { crv[0].fX = SkFloatToScalar(x0); crv[0].fY = SkFloatToScalar(y0); crv[1].fX = SkFloatToScalar(x1); crv[1].fY = SkFloatToScalar(y1); crv[2].fX = SkFloatToScalar(x2); crv[2].fY = SkFloatToScalar(y2); crv[3].fX = SkFloatToScalar(x3); crv[3].fY = SkFloatToScalar(y3); return crv; }
void svg_renderer::update_drawing (const QTransform &transform, const QRectF &rect_to_update, int cache_object_type) { m_cache->lock (); DO_ON_EXIT (m_cache->unlock ()); double cache_zoom_x = m_cache->zoom_x (); double cache_zoom_y = m_cache->zoom_y (); double cur_zoom_x = transform.m11 (); double cur_zoom_y = transform.m22 (); QRectF rect_to_draw = rect_to_update; QTransform real_transform = transform; SkBitmap bitmap; bitmap.setConfig (SkBitmap::kARGB_8888_Config, rect_to_draw.width (), rect_to_draw.height ()); bitmap.allocPixels (); SkBitmapDevice device (bitmap); SkCanvas canvas (&device); if (!are_equal (cache_zoom_x, cur_zoom_x) || !are_equal (cache_zoom_y, cur_zoom_y)) { QTransform scale_transform = QTransform::fromScale (cache_zoom_x / cur_zoom_x, cache_zoom_y / cur_zoom_y); real_transform = real_transform * scale_transform; canvas.setMatrix (qt2skia::matrix (scale_transform.inverted ())); rect_to_draw = scale_transform.mapRect (rect_to_draw); } canvas.drawColor (SK_ColorTRANSPARENT, SkXfermode::kSrc_Mode); pair<render_cache_id, render_cache_id> it_pair = render_cache_id::get_id_for_pixel_rect (real_transform, rect_to_draw, cache_object_type); for (int x = it_pair.first.x (); x <= it_pair.second.x (); x++) for (int y = it_pair.first.y (); y <= it_pair.second.y (); y++) { render_cache_id cur_id (x, y, cache_object_type); SkBitmap bitmap = m_cache->bitmap (cur_id); if (bitmap.empty ()) continue; QRectF pixel_rect = cur_id.pixel_rect (real_transform); canvas.drawBitmap (bitmap, SkFloatToScalar (pixel_rect.x ()), SkFloatToScalar (pixel_rect.y ())); } m_cache->set_current_screen (bitmap, cache_object_type); }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { SkColor color = graphicsContext->platformContext()->effectiveFillColor(); unsigned char alpha = SkColorGetA(color); // Skip 100% transparent text; no need to draw anything. if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke && !graphicsContext->hasShadow()) return; // We draw the glyphs in chunks to avoid having to do a heap allocation for // the arrays of characters and advances. const int kMaxBufferLength = 256; Vector<WORD, kMaxBufferLength> glyphs; Vector<int, kMaxBufferLength> advances; int glyphIndex = 0; // The starting glyph of the current chunk. // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position // of each glyph in floating point units and rounds to integer advances at the last possible moment. float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph. int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered. while (glyphIndex < numGlyphs) { // How many chars will be in this chunk? int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); glyphs.resize(curLen); advances.resize(curLen); float currentWidth = 0; for (int i = 0; i < curLen; ++i, ++glyphIndex) { glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex); advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded; lastHorizontalOffsetRounded += advances[i]; currentWidth += glyphBuffer.advanceAt(from + glyphIndex); // Bug 26088 - very large positive or negative runs can fail to // render so we clamp the size here. In the specs, negative // letter-spacing is implementation-defined, so this should be // fine, and it matches Safari's implementation. The call actually // seems to crash if kMaxNegativeRun is set to somewhere around // -32830, so we give ourselves a little breathing room. const int maxNegativeRun = -32768; const int maxPositiveRun = 32768; if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) advances[i] = 0; } SkPoint origin = point; origin.fX += SkFloatToScalar(horizontalOffset - point.x() - currentWidth); paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], 0, &origin); } }