String SVGTransformList::valueAsString() const { // TODO: We may want to build a real transform string, instead of concatting to a matrix(...). SVGTransform transform = concatenate(); if (transform.type() == SVGTransform::SVG_TRANSFORM_MATRIX) { AffineTransform matrix = transform.matrix(); return String::format("matrix(%f %f %f %f %f %f)", matrix.a(), matrix.b(), matrix.c(), matrix.d(), matrix.e(), matrix.f()); } return String(); }
// static void Shader::affineTo3x3(const AffineTransform& transform, float mat[9]) { mat[0] = transform.a(); mat[1] = transform.b(); mat[2] = 0.0f; mat[3] = transform.c(); mat[4] = transform.d(); mat[5] = 0.0f; mat[6] = transform.e(); mat[7] = transform.f(); mat[8] = 1.0f; }
static void drawDeferredFilter(GraphicsContext* context, FilterData* filterData, SVGFilterElement* filterElement) { SkiaImageFilterBuilder builder(context); SourceGraphic* sourceGraphic = static_cast<SourceGraphic*>(filterData->builder->getEffectById(SourceGraphic::effectName())); ASSERT(sourceGraphic); builder.setSourceGraphic(sourceGraphic); RefPtr<ImageFilter> imageFilter = builder.build(filterData->builder->lastEffect(), ColorSpaceDeviceRGB); FloatRect boundaries = filterData->boundaries; context->save(); // Clip drawing of filtered image to the minimum required paint rect. FilterEffect* lastEffect = filterData->builder->lastEffect(); context->clipRect(lastEffect->determineAbsolutePaintRect(lastEffect->maxEffectRect())); if (filterElement->hasAttribute(SVGNames::filterResAttr)) { // Get boundaries in device coords. // FIXME: See crbug.com/382491. Is the use of getCTM OK here, given it does not include device // zoom or High DPI adjustments? FloatSize size = context->getCTM().mapSize(boundaries.size()); // Compute the scale amount required so that the resulting offscreen is exactly filterResX by filterResY pixels. float filterResScaleX = filterElement->filterResX()->currentValue()->value() / size.width(); float filterResScaleY = filterElement->filterResY()->currentValue()->value() / size.height(); // Scale the CTM so the primitive is drawn to filterRes. context->scale(filterResScaleX, filterResScaleY); // Create a resize filter with the inverse scale. AffineTransform resizeMatrix; resizeMatrix.scale(1 / filterResScaleX, 1 / filterResScaleY); imageFilter = builder.buildTransform(resizeMatrix, imageFilter.get()); } // See crbug.com/382491. if (!RuntimeEnabledFeatures::slimmingPaintEnabled()) { // If the CTM contains rotation or shearing, apply the filter to // the unsheared/unrotated matrix, and do the shearing/rotation // as a final pass. AffineTransform ctm = context->getCTM(); if (ctm.b() || ctm.c()) { AffineTransform scaleAndTranslate; scaleAndTranslate.translate(ctm.e(), ctm.f()); scaleAndTranslate.scale(ctm.xScale(), ctm.yScale()); ASSERT(scaleAndTranslate.isInvertible()); AffineTransform shearAndRotate = scaleAndTranslate.inverse(); shearAndRotate.multiply(ctm); context->setCTM(scaleAndTranslate); imageFilter = builder.buildTransform(shearAndRotate, imageFilter.get()); } } context->beginLayer(1, CompositeSourceOver, &boundaries, ColorFilterNone, imageFilter.get()); context->endLayer(); context->restore(); }
static bool rotationOfCharacterCallback(QueryData* queryData, const SVGTextFragment& fragment) { RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData); int startPosition = data->position; int endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; if (!fragment.isTransformed()) { data->rotation = 0; } else { AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength); fragmentTransform.scale(1 / fragmentTransform.xScale(), 1 / fragmentTransform.yScale()); data->rotation = narrowPrecisionToFloat(rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a()))); } return true; }
SkMatrix affineTransformToSkMatrix(const AffineTransform& source) { SkMatrix result; result.setScaleX(WebCoreDoubleToSkScalar(source.a())); result.setSkewX(WebCoreDoubleToSkScalar(source.c())); result.setTranslateX(WebCoreDoubleToSkScalar(source.e())); result.setScaleY(WebCoreDoubleToSkScalar(source.d())); result.setSkewY(WebCoreDoubleToSkScalar(source.b())); result.setTranslateY(WebCoreDoubleToSkScalar(source.f())); // FIXME: Set perspective properly. result.setPerspX(0); result.setPerspY(0); result.set(SkMatrix::kMPersp2, SK_Scalar1); return result; }
bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const { RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData); unsigned startPosition = data->position; unsigned endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); if (fragmentTransform.isIdentity()) data->rotation = 0; else { fragmentTransform.scale(1 / fragmentTransform.xScale(), 1 / fragmentTransform.yScale()); data->rotation = narrowPrecisionToFloat(rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a()))); } return true; }
static void paintFilteredContent(const LayoutObject& object, GraphicsContext& context, FilterData* filterData) { ASSERT(filterData->m_state == FilterData::ReadyToPaint); ASSERT(filterData->filter->sourceGraphic()); filterData->m_state = FilterData::PaintingFilter; SkiaImageFilterBuilder builder; RefPtr<SkImageFilter> imageFilter = builder.build(filterData->filter->lastEffect(), ColorSpaceDeviceRGB); FloatRect boundaries = filterData->filter->filterRegion(); context.save(); // Clip drawing of filtered image to the minimum required paint rect. FilterEffect* lastEffect = filterData->filter->lastEffect(); context.clipRect(lastEffect->determineAbsolutePaintRect(lastEffect->maxEffectRect())); #ifdef CHECK_CTM_FOR_TRANSFORMED_IMAGEFILTER // TODO: Remove this workaround once skew/rotation support is added in Skia // (https://code.google.com/p/skia/issues/detail?id=3288, crbug.com/446935). // If the CTM contains rotation or shearing, apply the filter to // the unsheared/unrotated matrix, and do the shearing/rotation // as a final pass. AffineTransform ctm = SVGLayoutSupport::deprecatedCalculateTransformToLayer(&object); if (ctm.b() || ctm.c()) { AffineTransform scaleAndTranslate; scaleAndTranslate.translate(ctm.e(), ctm.f()); scaleAndTranslate.scale(ctm.xScale(), ctm.yScale()); ASSERT(scaleAndTranslate.isInvertible()); AffineTransform shearAndRotate = scaleAndTranslate.inverse(); shearAndRotate.multiply(ctm); context.concatCTM(shearAndRotate.inverse()); imageFilter = builder.buildTransform(shearAndRotate, imageFilter.get()); } #endif context.beginLayer(1, SkXfermode::kSrcOver_Mode, &boundaries, ColorFilterNone, imageFilter.get()); context.endLayer(); context.restore(); filterData->m_state = FilterData::ReadyToPaint; }