bool SkMagnifierImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context&, SkBitmap* dst, SkIPoint* offset) const { if ((src.colorType() != kN32_SkColorType) || (fSrcRect.width() >= src.width()) || (fSrcRect.height() >= src.height())) { return false; } SkAutoLockPixels alp(src); SkASSERT(src.getPixels()); if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height())); if (!device) { return false; } *dst = device->accessBitmap(false); SkAutoLockPixels alp_dst(*dst); SkScalar inv_inset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1; SkScalar inv_x_zoom = fSrcRect.width() / src.width(); SkScalar inv_y_zoom = fSrcRect.height() / src.height(); SkColor* sptr = src.getAddr32(0, 0); SkColor* dptr = dst->getAddr32(0, 0); int width = src.width(), height = src.height(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { SkScalar x_dist = SkMin32(x, width - x - 1) * inv_inset; SkScalar y_dist = SkMin32(y, height - y - 1) * inv_inset; SkScalar weight = 0; static const SkScalar kScalar2 = SkScalar(2); // To create a smooth curve at the corners, we need to work on // a square twice the size of the inset. if (x_dist < kScalar2 && y_dist < kScalar2) { x_dist = kScalar2 - x_dist; y_dist = kScalar2 - y_dist; SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) + SkScalarSquare(y_dist)); dist = SkMaxScalar(kScalar2 - dist, 0); weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1); } else { SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist), SkScalarSquare(y_dist)); weight = SkMinScalar(sqDist, SK_Scalar1); } SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * inv_x_zoom)) + (SK_Scalar1 - weight) * x; SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * inv_y_zoom)) + (SK_Scalar1 - weight) * y; int x_val = SkTPin(SkScalarFloorToInt(x_interp), 0, width - 1); int y_val = SkTPin(SkScalarFloorToInt(y_interp), 0, height - 1); *dptr = sptr[y_val * width + x_val]; dptr++; } } return true; }
bool SkPatchUtils::getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], int lodX, int lodY) { if (lodX < 1 || lodY < 1 || NULL == cubics || NULL == data) { return false; } // check for overflow in multiplication const int64_t lodX64 = (lodX + 1), lodY64 = (lodY + 1), mult64 = lodX64 * lodY64; if (mult64 > SK_MaxS32) { return false; } data->fVertexCount = SkToS32(mult64); // it is recommended to generate draw calls of no more than 65536 indices, so we never generate // more than 60000 indices. To accomplish that we resize the LOD and vertex count if (data->fVertexCount > 10000 || lodX > 200 || lodY > 200) { SkScalar weightX = static_cast<SkScalar>(lodX) / (lodX + lodY); SkScalar weightY = static_cast<SkScalar>(lodY) / (lodX + lodY); // 200 comes from the 100 * 2 which is the max value of vertices because of the limit of // 60000 indices ( sqrt(60000 / 6) that comes from data->fIndexCount = lodX * lodY * 6) lodX = static_cast<int>(weightX * 200); lodY = static_cast<int>(weightY * 200); data->fVertexCount = (lodX + 1) * (lodY + 1); } data->fIndexCount = lodX * lodY * 6; data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount); data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount); // if colors is not null then create array for colors SkPMColor colorsPM[kNumCorners]; if (NULL != colors) { // premultiply colors to avoid color bleeding. for (int i = 0; i < kNumCorners; i++) { colorsPM[i] = SkPreMultiplyColor(colors[i]); } data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount); } // if texture coordinates are not null then create array for them if (NULL != texCoords) { data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount); } SkPoint pts[kNumPtsCubic]; SkPatchUtils::getBottomCubic(cubics, pts); FwDCubicEvaluator fBottom(pts); SkPatchUtils::getTopCubic(cubics, pts); FwDCubicEvaluator fTop(pts); SkPatchUtils::getLeftCubic(cubics, pts); FwDCubicEvaluator fLeft(pts); SkPatchUtils::getRightCubic(cubics, pts); FwDCubicEvaluator fRight(pts); fBottom.restart(lodX); fTop.restart(lodX); SkScalar u = 0.0f; int stride = lodY + 1; for (int x = 0; x <= lodX; x++) { SkPoint bottom = fBottom.next(), top = fTop.next(); fLeft.restart(lodY); fRight.restart(lodY); SkScalar v = 0.f; for (int y = 0; y <= lodY; y++) { int dataIndex = x * (lodY + 1) + y; SkPoint left = fLeft.next(), right = fRight.next(); SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(), (1.0f - v) * top.y() + v * bottom.y()); SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(), (1.0f - u) * left.y() + u * right.y()); SkPoint s2 = SkPoint::Make( (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x() + u * fTop.getCtrlPoints()[3].x()) + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x() + u * fBottom.getCtrlPoints()[3].x()), (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y() + u * fTop.getCtrlPoints()[3].y()) + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y() + u * fBottom.getCtrlPoints()[3].y())); data->fPoints[dataIndex] = s0 + s1 - s2; if (NULL != colors) { uint8_t a = uint8_t(bilerp(u, v, SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])), SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])), SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])), SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner])))); uint8_t r = uint8_t(bilerp(u, v, SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])), SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])), SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])), SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner])))); uint8_t g = uint8_t(bilerp(u, v, SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])), SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])), SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])), SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner])))); uint8_t b = uint8_t(bilerp(u, v, SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])), SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])), SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])), SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner])))); data->fColors[dataIndex] = SkPackARGB32(a,r,g,b); } if (NULL != texCoords) { data->fTexCoords[dataIndex] = SkPoint::Make( bilerp(u, v, texCoords[kTopLeft_Corner].x(), texCoords[kTopRight_Corner].x(), texCoords[kBottomLeft_Corner].x(), texCoords[kBottomRight_Corner].x()), bilerp(u, v, texCoords[kTopLeft_Corner].y(), texCoords[kTopRight_Corner].y(), texCoords[kBottomLeft_Corner].y(), texCoords[kBottomRight_Corner].y())); } if(x < lodX && y < lodY) { int i = 6 * (x * lodY + y); data->fIndices[i] = x * stride + y; data->fIndices[i + 1] = x * stride + 1 + y; data->fIndices[i + 2] = (x + 1) * stride + 1 + y; data->fIndices[i + 3] = data->fIndices[i]; data->fIndices[i + 4] = data->fIndices[i + 2]; data->fIndices[i + 5] = (x + 1) * stride + y; } v = SkScalarClampMax(v + 1.f / lodY, 1); } u = SkScalarClampMax(u + 1.f / lodX, 1); } return true; }