// https://code.google.com/p/chromium/issues/detail?id=448299 // Giant (inverse) matrix causes overflow when converting/computing using 32.32 // Before the fix, we would assert (and then crash). static void test_big_grad(skiatest::Reporter* reporter) { const SkColor colors[] = { SK_ColorRED, SK_ColorBLUE }; const SkPoint pts[] = {{ 15, 14.7112684f }, { 0.709064007f, 12.6108112f }}; SkPaint paint; paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp)); SkBitmap bm; bm.allocN32Pixels(2000, 1); SkCanvas c(bm); const SkScalar affine[] = { 1.06608627e-06f, 4.26434525e-07f, 6.2855f, 2.6611f, 273.4393f, 244.0046f }; SkMatrix matrix; matrix.setAffine(affine); c.concat(matrix); c.drawPaint(paint); }
// This test case including path coords and matrix taken from crbug.com/627443. // Because of inaccuracies in large floating point values this causes the // the path renderer to attempt to add a path DF to its atlas that is larger // than the plot size which used to crash rather than fail gracefully. static void test_far_from_origin(GrDrawContext* drawContext, GrPathRenderer* pr, GrResourceProvider* rp) { SkPath path; path.lineTo(49.0255089839f, 0.473541f); static constexpr SkScalar mvals[] = {14.0348252854f, 2.13026182736f, 13.6122547187f, 118.309922702f, 1912337682.09f, 2105391889.87f}; SkMatrix matrix; matrix.setAffine(mvals); SkMatrix inverse; SkAssertResult(matrix.invert(&inverse)); path.transform(inverse); SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); rec.setStrokeStyle(1.f); rec.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 1.f); GrStyle style(rec, nullptr); GrShape shape(path, style); shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, 1.f); GrPaint paint; paint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::kSrc_Mode)); GrNoClip noClip; GrPathRenderer::DrawPathArgs args; args.fPaint = &paint; args.fUserStencilSettings = &GrUserStencilSettings::kUnused; args.fDrawContext = drawContext; args.fClip = &noClip; args.fResourceProvider = rp; args.fViewMatrix = &matrix; args.fShape = &shape; args.fAntiAlias = true; args.fGammaCorrect = false; args.fColor = 0x0; pr->drawPath(args); }
GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color, sk_sp<SkVertices> vertices, const SkVertices::Bone bones[], int boneCount, GrPrimitiveType primitiveType, GrAAType aaType, sk_sp<GrColorSpaceXform> colorSpaceXform, const SkMatrix& viewMatrix) : INHERITED(ClassID()) , fHelper(helperArgs, aaType) , fPrimitiveType(primitiveType) , fColorSpaceXform(std::move(colorSpaceXform)) { SkASSERT(vertices); fVertexCount = vertices->vertexCount(); fIndexCount = vertices->indexCount(); fColorArrayType = vertices->hasColors() ? ColorArrayType::kSkColor : ColorArrayType::kPremulGrColor; Mesh& mesh = fMeshes.push_back(); mesh.fColor = color; mesh.fViewMatrix = viewMatrix; mesh.fVertices = std::move(vertices); mesh.fIgnoreTexCoords = false; mesh.fIgnoreColors = false; mesh.fIgnoreBones = false; if (mesh.fVertices->hasBones() && bones) { // Perform the transformations on the CPU instead of the GPU. mesh.fVertices = mesh.fVertices->applyBones(bones, boneCount); } else { if (bones && boneCount > 1) { // NOTE: This should never be used. All bone transforms are being done on the CPU // instead of the GPU. // Copy the bone data. fBones.assign(bones, bones + boneCount); } } fFlags = 0; if (mesh.hasPerVertexColors()) { fFlags |= kRequiresPerVertexColors_Flag; } if (mesh.hasExplicitLocalCoords()) { fFlags |= kAnyMeshHasExplicitLocalCoords_Flag; } if (mesh.hasBones()) { fFlags |= kHasBones_Flag; } // Special case for meshes with a world transform but no bone weights. // These will be considered normal vertices draws without bones. if (!mesh.fVertices->hasBones() && boneCount == 1) { SkMatrix worldTransform; worldTransform.setAffine(bones[0].values); mesh.fViewMatrix.preConcat(worldTransform); } IsZeroArea zeroArea; if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) { zeroArea = IsZeroArea::kYes; } else { zeroArea = IsZeroArea::kNo; } if (this->hasBones()) { // We don't know the bounds if there are deformations involved, so attempt to calculate // the maximum possible. SkRect bounds = SkRect::MakeEmpty(); const SkRect originalBounds = bones[0].mapRect(mesh.fVertices->bounds()); for (int i = 1; i < boneCount; i++) { const SkVertices::Bone& matrix = bones[i]; bounds.join(matrix.mapRect(originalBounds)); } this->setTransformedBounds(bounds, mesh.fViewMatrix, HasAABloat::kNo, zeroArea); } else { this->setTransformedBounds(mesh.fVertices->bounds(), mesh.fViewMatrix, HasAABloat::kNo, zeroArea); } }