bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin) { SkScalar radius; if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) radius = fRadius; else radius = matrix.mapRadius(fRadius); // To avoid unseemly allocation requests (esp. for finite platforms like // handset) we limit the radius so something manageable. (as opposed to // 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, blurQuality)) { if (margin) { // we need to integralize radius for our margin, so take the ceil // just to be safe. margin->set(SkScalarCeil(radius), SkScalarCeil(radius)); } return true; } return false; }
Float Matrix::NativeMapRadius( /* [in] */ Int64 matrixHandle, /* [in] */ Float radius) { SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); Float result; result = SkScalarToFloat(matrix->mapRadius(radius)); return static_cast<Float>(result); }
bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin) const { SkScalar sigma = matrix.mapRadius(fBlurSigma); if (!SkBlurMask::BoxBlur(dst, src, sigma, SkBlurMask::kInner_Style, SkBlurMask::kLow_Quality)) { return false; } dst->fFormat = SkMask::k3D_Format; if (margin) { margin->set(SkScalarCeilToInt(3*sigma), SkScalarCeilToInt(3*sigma)); } if (src.fImage == NULL) { return true; } // create a larger buffer for the other two channels (should force fBlur to do this for us) { uint8_t* alphaPlane = dst->fImage; size_t planeSize = dst->computeImageSize(); if (0 == planeSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(planeSize * 3); memcpy(dst->fImage, alphaPlane, planeSize); SkMask::FreeImage(alphaPlane); } // run the light direction through the matrix... Light light = fLight; matrix.mapVectors((SkVector*)(void*)light.fDirection, (SkVector*)(void*)fLight.fDirection, 1); // now restore the length of the XY component // cast to SkVector so we can call setLength (this double cast silences alias warnings) SkVector* vec = (SkVector*)(void*)light.fDirection; vec->setLength(light.fDirection[0], light.fDirection[1], SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1])); SkEmbossMask::Emboss(dst, light); // restore original alpha memcpy(dst->fImage, src.fImage, src.computeImageSize()); return true; }
SkScalar GrPathUtils::scaleToleranceToSrc(SkScalar devTol, const SkMatrix& viewM, const SkRect& pathBounds) { // In order to tesselate the path we get a bound on how much the matrix can // scale when mapping to screen coordinates. SkScalar stretch = viewM.getMaxScale(); SkScalar srcTol = devTol; if (stretch < 0) { // take worst case mapRadius amoung four corners. // (less than perfect) for (int i = 0; i < 4; ++i) { SkMatrix mat; mat.setTranslate((i % 2) ? pathBounds.fLeft : pathBounds.fRight, (i < 2) ? pathBounds.fTop : pathBounds.fBottom); mat.postConcat(viewM); stretch = SkMaxScalar(stretch, mat.mapRadius(SK_Scalar1)); } } return srcTol / stretch; }
SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) : SkPDFDict("Pattern"), fState(state) { SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL; SkPoint transformPoints[2]; // Depending on the type of the gradient, we want to transform the // coordinate space in different ways. const SkShader::GradientInfo* info = &fState.get()->fInfo; transformPoints[0] = info->fPoint[0]; transformPoints[1] = info->fPoint[1]; switch (fState.get()->fType) { case SkShader::kLinear_GradientType: codeFunction = &linearCode; break; case SkShader::kRadial_GradientType: transformPoints[1] = transformPoints[0]; transformPoints[1].fX += info->fRadius[0]; codeFunction = &radialCode; break; case SkShader::kRadial2_GradientType: { // Bail out if the radii are the same. Empty fResources signals // an error and isValid will return false. if (info->fRadius[0] == info->fRadius[1]) { return; } transformPoints[1] = transformPoints[0]; SkScalar dr = info->fRadius[1] - info->fRadius[0]; transformPoints[1].fX += dr; codeFunction = &twoPointRadialCode; break; } case SkShader::kSweep_GradientType: transformPoints[1] = transformPoints[0]; transformPoints[1].fX += 1; codeFunction = &sweepCode; break; case SkShader::kColor_GradientType: case SkShader::kNone_GradientType: default: return; } // Move any scaling (assuming a unit gradient) or translation // (and rotation for linear gradient), of the final gradient from // info->fPoints to the matrix (updating bbox appropriately). Now // the gradient can be drawn on on the unit segment. SkMatrix mapperMatrix; unitToPointsMatrix(transformPoints, &mapperMatrix); SkMatrix finalMatrix = fState.get()->fCanvasTransform; finalMatrix.preConcat(mapperMatrix); finalMatrix.preConcat(fState.get()->fShaderTransform); SkRect bbox; bbox.set(fState.get()->fBBox); transformBBox(finalMatrix, &bbox); SkRefPtr<SkPDFArray> domain = new SkPDFArray; domain->unref(); // SkRefPtr and new both took a reference. domain->reserve(4); domain->appendScalar(bbox.fLeft); domain->appendScalar(bbox.fRight); domain->appendScalar(bbox.fTop); domain->appendScalar(bbox.fBottom); SkString functionCode; // The two point radial gradient further references fState.get()->fInfo // in translating from x, y coordinates to the t parameter. So, we have // to transform the points and radii according to the calculated matrix. if (fState.get()->fType == SkShader::kRadial2_GradientType) { SkShader::GradientInfo twoPointRadialInfo = *info; SkMatrix inverseMapperMatrix; mapperMatrix.invert(&inverseMapperMatrix); inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); twoPointRadialInfo.fRadius[0] = inverseMapperMatrix.mapRadius(info->fRadius[0]); twoPointRadialInfo.fRadius[1] = inverseMapperMatrix.mapRadius(info->fRadius[1]); functionCode = codeFunction(twoPointRadialInfo); } else { functionCode = codeFunction(*info); } SkRefPtr<SkPDFStream> function = makePSFunction(functionCode, domain.get()); // Pass one reference to fResources, SkRefPtr and new both took a reference. fResources.push(function.get()); SkRefPtr<SkPDFDict> pdfShader = new SkPDFDict; pdfShader->unref(); // SkRefPtr and new both took a reference. pdfShader->insertInt("ShadingType", 1); pdfShader->insertName("ColorSpace", "DeviceRGB"); pdfShader->insert("Domain", domain.get()); pdfShader->insert("Function", new SkPDFObjRef(function.get()))->unref(); insertInt("PatternType", 2); insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); insert("Shading", pdfShader.get()); }
SkPDFFunctionShader* SkPDFFunctionShader::Create( SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) { const SkPDFShader::State& state = **autoState; SkString (*codeFunction)(const SkShader::GradientInfo& info, const SkMatrix& perspectiveRemover) = NULL; SkPoint transformPoints[2]; // Depending on the type of the gradient, we want to transform the // coordinate space in different ways. const SkShader::GradientInfo* info = &state.fInfo; transformPoints[0] = info->fPoint[0]; transformPoints[1] = info->fPoint[1]; switch (state.fType) { case SkShader::kLinear_GradientType: codeFunction = &linearCode; break; case SkShader::kRadial_GradientType: transformPoints[1] = transformPoints[0]; transformPoints[1].fX += info->fRadius[0]; codeFunction = &radialCode; break; case SkShader::kRadial2_GradientType: { // Bail out if the radii are the same. if (info->fRadius[0] == info->fRadius[1]) { return NULL; } transformPoints[1] = transformPoints[0]; SkScalar dr = info->fRadius[1] - info->fRadius[0]; transformPoints[1].fX += dr; codeFunction = &twoPointRadialCode; break; } case SkShader::kConical_GradientType: { transformPoints[1] = transformPoints[0]; transformPoints[1].fX += SK_Scalar1; codeFunction = &twoPointConicalCode; break; } case SkShader::kSweep_GradientType: transformPoints[1] = transformPoints[0]; transformPoints[1].fX += SK_Scalar1; codeFunction = &sweepCode; break; case SkShader::kColor_GradientType: case SkShader::kNone_GradientType: default: return NULL; } // Move any scaling (assuming a unit gradient) or translation // (and rotation for linear gradient), of the final gradient from // info->fPoints to the matrix (updating bbox appropriately). Now // the gradient can be drawn on on the unit segment. SkMatrix mapperMatrix; unitToPointsMatrix(transformPoints, &mapperMatrix); SkMatrix finalMatrix = state.fCanvasTransform; finalMatrix.preConcat(state.fShaderTransform); finalMatrix.preConcat(mapperMatrix); // Preserves as much as posible in the final matrix, and only removes // the perspective. The inverse of the perspective is stored in // perspectiveInverseOnly matrix and has 3 useful numbers // (p0, p1, p2), while everything else is either 0 or 1. // In this way the shader will handle it eficiently, with minimal code. SkMatrix perspectiveInverseOnly = SkMatrix::I(); if (finalMatrix.hasPerspective()) { if (!split_perspective(finalMatrix, &finalMatrix, &perspectiveInverseOnly)) { return NULL; } } SkRect bbox; bbox.set(state.fBBox); if (!inverse_transform_bbox(finalMatrix, &bbox)) { return NULL; } SkAutoTUnref<SkPDFArray> domain(new SkPDFArray); domain->reserve(4); domain->appendScalar(bbox.fLeft); domain->appendScalar(bbox.fRight); domain->appendScalar(bbox.fTop); domain->appendScalar(bbox.fBottom); SkString functionCode; // The two point radial gradient further references // state.fInfo // in translating from x, y coordinates to the t parameter. So, we have // to transform the points and radii according to the calculated matrix. if (state.fType == SkShader::kRadial2_GradientType) { SkShader::GradientInfo twoPointRadialInfo = *info; SkMatrix inverseMapperMatrix; if (!mapperMatrix.invert(&inverseMapperMatrix)) { return NULL; } inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); twoPointRadialInfo.fRadius[0] = inverseMapperMatrix.mapRadius(info->fRadius[0]); twoPointRadialInfo.fRadius[1] = inverseMapperMatrix.mapRadius(info->fRadius[1]); functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); } else { functionCode = codeFunction(*info, perspectiveInverseOnly); } SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict); pdfShader->insertInt("ShadingType", 1); pdfShader->insertName("ColorSpace", "DeviceRGB"); pdfShader->insert("Domain", domain.get()); SkAutoTUnref<SkPDFStream> function( make_ps_function(functionCode, domain.get())); pdfShader->insert("Function", new SkPDFObjRef(function))->unref(); SkAutoTUnref<SkPDFArray> matrixArray( SkPDFUtils::MatrixToArray(finalMatrix)); SkPDFFunctionShader* pdfFunctionShader = SkNEW_ARGS(SkPDFFunctionShader, (autoState->detach())); pdfFunctionShader->insertInt("PatternType", 2); pdfFunctionShader->insert("Matrix", matrixArray.get()); pdfFunctionShader->insert("Shading", pdfShader.get()); canon->addFunctionShader(pdfFunctionShader); return pdfFunctionShader; }
static jfloat mapRadius(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloat radius) { SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); float result; result = SkScalarToFloat(matrix->mapRadius(radius)); return static_cast<jfloat>(result); }
static SkPDFIndirectReference make_function_shader(SkPDFDocument* doc, const SkPDFGradientShader::Key& state) { SkPoint transformPoints[2]; const SkShader::GradientInfo& info = state.fInfo; SkMatrix finalMatrix = state.fCanvasTransform; finalMatrix.preConcat(state.fShaderTransform); bool doStitchFunctions = (state.fType == SkShader::kLinear_GradientType || state.fType == SkShader::kRadial_GradientType || state.fType == SkShader::kConical_GradientType) && (SkTileMode)info.fTileMode == SkTileMode::kClamp && !finalMatrix.hasPerspective(); int32_t shadingType = 1; auto pdfShader = SkPDFMakeDict(); // The two point radial gradient further references // state.fInfo // in translating from x, y coordinates to the t parameter. So, we have // to transform the points and radii according to the calculated matrix. if (doStitchFunctions) { pdfShader->insertObject("Function", gradientStitchCode(info)); shadingType = (state.fType == SkShader::kLinear_GradientType) ? 2 : 3; auto extend = SkPDFMakeArray(); extend->reserve(2); extend->appendBool(true); extend->appendBool(true); pdfShader->insertObject("Extend", std::move(extend)); std::unique_ptr<SkPDFArray> coords; if (state.fType == SkShader::kConical_GradientType) { SkScalar r1 = info.fRadius[0]; SkScalar r2 = info.fRadius[1]; SkPoint pt1 = info.fPoint[0]; SkPoint pt2 = info.fPoint[1]; FixUpRadius(pt1, r1, pt2, r2); coords = SkPDFMakeArray(pt1.x(), pt1.y(), r1, pt2.x(), pt2.y(), r2); } else if (state.fType == SkShader::kRadial_GradientType) { const SkPoint& pt1 = info.fPoint[0]; coords = SkPDFMakeArray(pt1.x(), pt1.y(), 0, pt1.x(), pt1.y(), info.fRadius[0]); } else { const SkPoint& pt1 = info.fPoint[0]; const SkPoint& pt2 = info.fPoint[1]; coords = SkPDFMakeArray(pt1.x(), pt1.y(), pt2.x(), pt2.y()); } pdfShader->insertObject("Coords", std::move(coords)); } else { // Depending on the type of the gradient, we want to transform the // coordinate space in different ways. transformPoints[0] = info.fPoint[0]; transformPoints[1] = info.fPoint[1]; switch (state.fType) { case SkShader::kLinear_GradientType: break; case SkShader::kRadial_GradientType: transformPoints[1] = transformPoints[0]; transformPoints[1].fX += info.fRadius[0]; break; case SkShader::kConical_GradientType: { transformPoints[1] = transformPoints[0]; transformPoints[1].fX += SK_Scalar1; break; } case SkShader::kSweep_GradientType: transformPoints[1] = transformPoints[0]; transformPoints[1].fX += SK_Scalar1; break; case SkShader::kColor_GradientType: case SkShader::kNone_GradientType: default: return SkPDFIndirectReference(); } // Move any scaling (assuming a unit gradient) or translation // (and rotation for linear gradient), of the final gradient from // info.fPoints to the matrix (updating bbox appropriately). Now // the gradient can be drawn on on the unit segment. SkMatrix mapperMatrix; unit_to_points_matrix(transformPoints, &mapperMatrix); finalMatrix.preConcat(mapperMatrix); // Preserves as much as possible in the final matrix, and only removes // the perspective. The inverse of the perspective is stored in // perspectiveInverseOnly matrix and has 3 useful numbers // (p0, p1, p2), while everything else is either 0 or 1. // In this way the shader will handle it eficiently, with minimal code. SkMatrix perspectiveInverseOnly = SkMatrix::I(); if (finalMatrix.hasPerspective()) { if (!split_perspective(finalMatrix, &finalMatrix, &perspectiveInverseOnly)) { return SkPDFIndirectReference(); } } SkRect bbox; bbox.set(state.fBBox); if (!SkPDFUtils::InverseTransformBBox(finalMatrix, &bbox)) { return SkPDFIndirectReference(); } SkDynamicMemoryWStream functionCode; SkShader::GradientInfo infoCopy = info; if (state.fType == SkShader::kConical_GradientType) { SkMatrix inverseMapperMatrix; if (!mapperMatrix.invert(&inverseMapperMatrix)) { return SkPDFIndirectReference(); } inverseMapperMatrix.mapPoints(infoCopy.fPoint, 2); infoCopy.fRadius[0] = inverseMapperMatrix.mapRadius(info.fRadius[0]); infoCopy.fRadius[1] = inverseMapperMatrix.mapRadius(info.fRadius[1]); } switch (state.fType) { case SkShader::kLinear_GradientType: linearCode(infoCopy, perspectiveInverseOnly, &functionCode); break; case SkShader::kRadial_GradientType: radialCode(infoCopy, perspectiveInverseOnly, &functionCode); break; case SkShader::kConical_GradientType: twoPointConicalCode(infoCopy, perspectiveInverseOnly, &functionCode); break; case SkShader::kSweep_GradientType: sweepCode(infoCopy, perspectiveInverseOnly, &functionCode); break; default: SkASSERT(false); } pdfShader->insertObject( "Domain", SkPDFMakeArray(bbox.left(), bbox.right(), bbox.top(), bbox.bottom())); auto domain = SkPDFMakeArray(bbox.left(), bbox.right(), bbox.top(), bbox.bottom()); std::unique_ptr<SkPDFArray> rangeObject = SkPDFMakeArray(0, 1, 0, 1, 0, 1); pdfShader->insertRef("Function", make_ps_function(functionCode.detachAsStream(), std::move(domain), std::move(rangeObject), doc)); } pdfShader->insertInt("ShadingType", shadingType); pdfShader->insertName("ColorSpace", "DeviceRGB"); SkPDFDict pdfFunctionShader("Pattern"); pdfFunctionShader.insertInt("PatternType", 2); pdfFunctionShader.insertObject("Matrix", SkPDFUtils::MatrixToArray(finalMatrix)); pdfFunctionShader.insertObject("Shading", std::move(pdfShader)); return doc->emit(pdfFunctionShader); }