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; }
// doesn't work yet void comparePathsTiny(const SkPath& one, const SkPath& two) { const SkRect& bounds1 = one.getBounds(); const SkRect& bounds2 = two.getBounds(); SkRect larger = bounds1; larger.join(bounds2); SkBitmap bits; int bitWidth = SkScalarCeil(larger.width()) + 2; int bitHeight = SkScalarCeil(larger.height()) + 2; bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight); bits.allocPixels(); SkCanvas canvas(bits); canvas.drawColor(SK_ColorWHITE); SkPaint paint; canvas.save(); canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); canvas.drawPath(one, paint); canvas.restore(); canvas.save(); canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1); canvas.drawPath(two, paint); canvas.restore(); for (int y = 0; y < bitHeight; ++y) { uint8_t* addr1 = bits.getAddr1(0, y); uint8_t* addr2 = bits.getAddr1(bitWidth, y); for (int x = 0; x < bits.rowBytes(); ++x) { SkASSERT(addr1[x] == addr2[x]); } } }
IntRect OpaqueRegionSkia::asRect() const { // Returns the largest enclosed rect. int left = SkScalarCeil(m_opaqueRect.fLeft); int top = SkScalarCeil(m_opaqueRect.fTop); int right = SkScalarFloor(m_opaqueRect.fRight); int bottom = SkScalarFloor(m_opaqueRect.fBottom); return IntRect(left, top, right-left, bottom-top); }
bool drawAsciiPaths(const SkPath& one, const SkPath& two, bool drawPaths) { if (!drawPaths) { return true; } if (gShowAsciiPaths) { showPath(one, "one:"); showPath(two, "two:"); } const SkRect& bounds1 = one.getBounds(); const SkRect& bounds2 = two.getBounds(); SkRect larger = bounds1; larger.join(bounds2); SkBitmap bits; char out[256]; int bitWidth = SkScalarCeil(larger.width()) + 2; if (bitWidth * 2 + 1 >= (int) sizeof(out)) { return false; } int bitHeight = SkScalarCeil(larger.height()) + 2; if (bitHeight >= (int) sizeof(out)) { return false; } bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight); bits.allocPixels(); SkCanvas canvas(bits); canvas.drawColor(SK_ColorWHITE); SkPaint paint; canvas.save(); canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); canvas.drawPath(one, paint); canvas.restore(); canvas.save(); canvas.translate(-bounds2.fLeft + 1 + bitWidth, -bounds2.fTop + 1); canvas.drawPath(two, paint); canvas.restore(); for (int y = 0; y < bitHeight; ++y) { uint32_t* addr1 = bits.getAddr32(0, y); int x; char* outPtr = out; for (x = 0; x < bitWidth; ++x) { *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; } *outPtr++ = '|'; for (x = bitWidth; x < bitWidth * 2; ++x) { *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; } *outPtr++ = '\0'; SkDebugf("%s\n", out); } return true; }
bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin) { SkScalar radius = matrix.mapRadius(fBlurRadius); if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style, SkBlurMask::kLow_Quality)) { return false; } dst->fFormat = SkMask::k3D_Format; if (margin) { margin->set(SkScalarCeil(radius), SkScalarCeil(radius)); } 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; }
uint32_t GrPathUtils::cubicPointCount(const GrPoint points[], GrScalar tol) { if (tol < gMinCurveTol) { tol == gMinCurveTol; } GrAssert(tol > 0); GrScalar d = GrMax( points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]), points[2].distanceToLineSegmentBetweenSqd(points[0], points[3])); d = SkScalarSqrt(d); if (d <= tol) { return 1; } else { int temp = SkScalarCeil(SkScalarSqrt(SkScalarDiv(d, tol))); int pow2 = GrNextPow2(temp); // Because of NaNs & INFs we can wind up with a degenerate temp // such that pow2 comes out negative. Also, our point generator // will always output at least one pt. if (pow2 < 1) { pow2 = 1; } return GrMin(pow2, MAX_POINTS_PER_CURVE); } }
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; } }
uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[], GrScalar tol) { if (tol < gMinCurveTol) { tol == gMinCurveTol; } GrAssert(tol > 0); GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]); if (d <= tol) { return 1; } else { // Each time we subdivide, d should be cut in 4. So we need to // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x) // points. // 2^(log4(x)) = sqrt(x); int temp = SkScalarCeil(SkScalarSqrt(SkScalarDiv(d, tol))); int pow2 = GrNextPow2(temp); // Because of NaNs & INFs we can wind up with a degenerate temp // such that pow2 comes out negative. Also, our point generator // will always output at least one pt. if (pow2 < 1) { pow2 = 1; } return GrMin(pow2, MAX_POINTS_PER_CURVE); } }
bool CursorRing::setup() { m_node->localCursorRings(m_frame, &m_rings); if (!m_rings.size()) { DBG_NAV_LOG("!rings.size()"); m_viewImpl->m_hasCursorBounds = false; return false; } m_isButton = false; m_viewImpl->gButtonMutex.lock(); // If this is a button drawn by us (rather than webkit) do not draw the // cursor ring, since its cursor will be shown by a change in what we draw. // Should be in sync with recordButtons, since that will be called // before this. if (m_viewImpl->m_buttons.size() > 0) { WebCore::Node* cursorPointer = (WebCore::Node*) m_node->nodePointer(); Container* end = m_viewImpl->m_buttons.end(); for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) { if (ptr->matches(cursorPointer)) { m_isButton = true; break; } } } m_viewImpl->gButtonMutex.unlock(); m_bounds = m_node->localBounds(m_frame); m_viewImpl->updateCursorBounds(m_root, m_frame, m_node); bool useHitBounds = m_node->useHitBounds(); if (useHitBounds) m_bounds = m_node->localHitBounds(m_frame); if (useHitBounds || m_node->useBounds()) { m_rings.clear(); m_rings.append(m_bounds); } m_bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER)); if (!m_node->hasCursorRing() || (m_node->isPlugin() && m_node->isFocus())) return false; m_flavor = NORMAL_FLAVOR; if (!m_isButton) { m_flavor = m_node->isSyntheticLink() ? FAKE_FLAVOR : NORMAL_FLAVOR; if (m_followedLink) { m_flavor = static_cast<Flavor>(m_flavor + NORMAL_ANIMATING); } #if DEBUG_NAV_UI const WebCore::IntRect& ring = m_rings[0]; DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d" " (%d, %d, %d, %d) isPlugin=%s", m_node->index(), m_node->nodePointer(), m_flavor == FAKE_FLAVOR ? "FAKE_FLAVOR" : m_flavor == NORMAL_ANIMATING ? "NORMAL_ANIMATING" : m_flavor == FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR", m_rings.size(), ring.x(), ring.y(), ring.width(), ring.height(), m_node->isPlugin() ? "true" : "false"); #endif } return true; }
static int pathsDrawTheSame(const SkPath& one, const SkPath& two, SkBitmap& bits, SkCanvas* c) { SkCanvas* canvasPtr = c; if (!c) { canvasPtr = new SkCanvas(bits); } const SkRect& bounds1 = one.getBounds(); const SkRect& bounds2 = two.getBounds(); SkRect larger = bounds1; larger.join(bounds2); int bitWidth = SkScalarCeil(larger.width()) + 2; int bitHeight = SkScalarCeil(larger.height()) + 2; if (bits.width() < bitWidth * 2 || bits.height() < bitHeight) { if (bits.width() >= 200) { SkDebugf("%s bitWidth=%d bitHeight=%d\n", __FUNCTION__, bitWidth, bitHeight); } bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight); bits.allocPixels(); canvasPtr->setBitmapDevice(bits); } SkCanvas& canvas = *canvasPtr; canvas.drawColor(SK_ColorWHITE); SkPaint paint; canvas.save(); canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); canvas.drawPath(one, paint); canvas.restore(); canvas.save(); canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); canvas.drawPath(two, paint); canvas.restore(); int errors = 0; for (int y = 0; y < bitHeight; ++y) { uint32_t* addr1 = bits.getAddr32(0, y); uint32_t* addr2 = bits.getAddr32(bitWidth, y); for (int x = 0; x < bitWidth; ++x) { errors += addr1[x] != addr2[x]; } } if (!c) { delete canvasPtr; } return errors; }
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRegion rgn; SkRegion clip; SkPath::FillType originalFillType = originalPath->getFillType(); const SkPath* path = originalPath; SkPath scaledPath; int scale = 1; SkRect bounds; // FIXME: This #ifdef can go away once we're firmly using the new Skia. // During the transition, this makes the code compatible with both versions. #ifdef SK_USE_OLD_255_TO_256 bounds = originalPath->getBounds(); #else originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType); #endif // We can immediately return false if the point is outside the bounding rect if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) return false; originalPath->setFillType(ft); // Skia has trouble with coordinates close to the max signed 16-bit values // If we have those, we need to scale. // // TODO: remove this code once Skia is patched to work properly with large // values const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (biggestCoord > kMaxCoordinate) { scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); SkMatrix m; m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); originalPath->transform(m, &scaledPath); path = &scaledPath; } int x = static_cast<int>(floorf(point.x() / scale)); int y = static_cast<int>(floorf(point.y() / scale)); clip.setRect(x, y, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); originalPath->setFillType(originalFillType); return contains; }
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRegion rgn; SkRegion clip; SkPath::FillType originalFillType = originalPath->getFillType(); const SkPath* path = originalPath; SkPath scaledPath; int scale = 1; 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; originalPath->setFillType(ft); // Skia has trouble with coordinates close to the max signed 16-bit values // If we have those, we need to scale. // // TODO: remove this code once Skia is patched to work properly with large // values const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (biggestCoord > kMaxCoordinate) { scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); SkMatrix m; m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); originalPath->transform(m, &scaledPath); path = &scaledPath; } int x = static_cast<int>(floorf(point.x() / scale)); int y = static_cast<int>(floorf(point.y() / scale)); clip.setRect(x - 1, y - 1, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); originalPath->setFillType(originalFillType); return contains; }
static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) { NPE_CHECK_RETURN_ZERO(env, paint); SkPaint::FontMetrics metrics; GraphicsJNI::getNativePaint(env, paint)->getFontMetrics(&metrics); int ascent = SkScalarRound(metrics.fAscent); int descent = SkScalarRound(metrics.fDescent); int leading = SkScalarRound(metrics.fLeading); if (metricsObj) { SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class)); env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloor(metrics.fTop)); env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent); env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent); env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeil(metrics.fBottom)); env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading); } return descent - ascent + leading; }
void SkDisplayMath::executeFunction(SkDisplayable* target, int index, SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, SkScriptValue* scriptValue) { if (scriptValue == NULL) return; SkASSERT(target == this); SkScriptValue* array = parameters.begin(); SkScriptValue* end = parameters.end(); SkScalar input = parameters[0].fOperand.fScalar; SkScalar scalarResult; switch (index) { case SK_FUNCTION(abs): scalarResult = SkScalarAbs(input); break; case SK_FUNCTION(acos): scalarResult = SkScalarACos(input); break; case SK_FUNCTION(asin): scalarResult = SkScalarASin(input); break; case SK_FUNCTION(atan): scalarResult = SkScalarATan2(input, SK_Scalar1); break; case SK_FUNCTION(atan2): scalarResult = SkScalarATan2(input, parameters[1].fOperand.fScalar); break; case SK_FUNCTION(ceil): scalarResult = SkIntToScalar(SkScalarCeil(input)); break; case SK_FUNCTION(cos): scalarResult = SkScalarCos(input); break; case SK_FUNCTION(exp): scalarResult = SkScalarExp(input); break; case SK_FUNCTION(floor): scalarResult = SkIntToScalar(SkScalarFloor(input)); break; case SK_FUNCTION(log): scalarResult = SkScalarLog(input); break; case SK_FUNCTION(max): scalarResult = -SK_ScalarMax; while (array < end) { scalarResult = SkMaxScalar(scalarResult, array->fOperand.fScalar); array++; } break; case SK_FUNCTION(min): scalarResult = SK_ScalarMax; while (array < end) { scalarResult = SkMinScalar(scalarResult, array->fOperand.fScalar); array++; } break; case SK_FUNCTION(pow): // not the greatest -- but use x^y = e^(y * ln(x)) scalarResult = SkScalarLog(input); scalarResult = SkScalarMul(parameters[1].fOperand.fScalar, scalarResult); scalarResult = SkScalarExp(scalarResult); break; case SK_FUNCTION(random): scalarResult = fRandom.nextUScalar1(); break; case SK_FUNCTION(round): scalarResult = SkIntToScalar(SkScalarRound(input)); break; case SK_FUNCTION(sin): scalarResult = SkScalarSin(input); break; case SK_FUNCTION(sqrt): { SkASSERT(parameters.count() == 1); SkASSERT(type == SkType_Float); scalarResult = SkScalarSqrt(input); } break; case SK_FUNCTION(tan): scalarResult = SkScalarTan(input); break; default: SkASSERT(0); scalarResult = SK_ScalarNaN; } scriptValue->fOperand.fScalar = scalarResult; scriptValue->fType = SkType_Float; }
SkRTree::Branch SkRTree::bulkLoad(SkTDArray<Branch>* branches, int level) { if (branches->count() == 1) { // Only one branch: it will be the root Branch out = (*branches)[0]; branches->rewind(); return out; } else { // First we sort the whole list by y coordinates SkQSort<int, Branch>(level, branches->begin(), branches->end() - 1, &RectLessY); int numBranches = branches->count() / fMaxChildren; int remainder = branches->count() % fMaxChildren; int newBranches = 0; if (0 != remainder) { ++numBranches; // If the remainder isn't enough to fill a node, we'll need to add fewer nodes to // some other branches to make up for it if (remainder >= fMinChildren) { remainder = 0; } else { remainder = fMinChildren - remainder; } } int numStrips = SkScalarCeil(SkScalarSqrt(SkIntToScalar(numBranches) * SkScalarInvert(fAspectRatio))); int numTiles = SkScalarCeil(SkIntToScalar(numBranches) / SkIntToScalar(numStrips)); int currentBranch = 0; for (int i = 0; i < numStrips; ++i) { int begin = currentBranch; int end = currentBranch + numTiles * fMaxChildren - SkMin32(remainder, (fMaxChildren - fMinChildren) * numTiles); if (end > branches->count()) { end = branches->count(); } // Now we sort horizontal strips of rectangles by their x coords SkQSort<int, Branch>(level, branches->begin() + begin, branches->begin() + end - 1, &RectLessX); for (int j = 0; j < numTiles && currentBranch < branches->count(); ++j) { int incrementBy = fMaxChildren; if (remainder != 0) { // if need be, omit some nodes to make up for remainder if (remainder <= fMaxChildren - fMinChildren) { incrementBy -= remainder; remainder = 0; } else { incrementBy = fMinChildren; remainder -= fMaxChildren - fMinChildren; } } Node* n = allocateNode(level); n->fNumChildren = 1; *n->child(0) = (*branches)[currentBranch]; Branch b; b.fBounds = (*branches)[currentBranch].fBounds; b.fChild.subtree = n; ++currentBranch; for (int k = 1; k < incrementBy && currentBranch < branches->count(); ++k) { b.fBounds.join((*branches)[currentBranch].fBounds); *n->child(k) = (*branches)[currentBranch]; ++n->fNumChildren; ++currentBranch; } (*branches)[newBranches] = b; ++newBranches; } } branches->setCount(newBranches); return this->bulkLoad(branches, level + 1); } }
bool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar provided_radius, Style style, SkIPoint* margin) { if (src.fFormat != SkMask::kA8_Format) { return false; } float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor)); float stddev = SkScalarToFloat(radius) /2.0f; float variance = stddev * stddev; int windowSize = SkScalarCeil(stddev*4); // round window size up to nearest odd number windowSize |= 1; SkAutoTMalloc<float> gaussWindow(windowSize); int halfWindow = windowSize >> 1; gaussWindow[halfWindow] = 1; float windowSum = 1; for (int x = 1 ; x <= halfWindow ; ++x) { float gaussian = expf(-x*x / variance); gaussWindow[halfWindow + x] = gaussWindow[halfWindow-x] = gaussian; windowSum += 2*gaussian; } // leave the filter un-normalized for now; we will divide by the normalization // sum later; int pad = halfWindow; if (margin) { margin->set( pad, pad ); } dst->fBounds = src.fBounds; dst->fBounds.outset(pad, pad); dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = NULL; if (src.fImage) { size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } int srcWidth = src.fBounds.width(); int srcHeight = src.fBounds.height(); int dstWidth = dst->fBounds.width(); const uint8_t* srcPixels = src.fImage; uint8_t* dstPixels = SkMask::AllocImage(dstSize); SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dstPixels); // do the actual blur. First, make a padded copy of the source. // use double pad so we never have to check if we're outside anything int padWidth = srcWidth + 4*pad; int padHeight = srcHeight; int padSize = padWidth * padHeight; SkAutoTMalloc<uint8_t> padPixels(padSize); memset(padPixels, 0, padSize); for (int y = 0 ; y < srcHeight; ++y) { uint8_t* padptr = padPixels + y * padWidth + 2*pad; const uint8_t* srcptr = srcPixels + y * srcWidth; memcpy(padptr, srcptr, srcWidth); } // blur in X, transposing the result into a temporary floating point buffer. // also double-pad the intermediate result so that the second blur doesn't // have to do extra conditionals. int tmpWidth = padHeight + 4*pad; int tmpHeight = padWidth - 2*pad; int tmpSize = tmpWidth * tmpHeight; SkAutoTMalloc<float> tmpImage(tmpSize); memset(tmpImage, 0, tmpSize*sizeof(tmpImage[0])); for (int y = 0 ; y < padHeight ; ++y) { uint8_t *srcScanline = padPixels + y*padWidth; for (int x = pad ; x < padWidth - pad ; ++x) { float *outPixel = tmpImage + (x-pad)*tmpWidth + y + 2*pad; // transposed output uint8_t *windowCenter = srcScanline + x; for (int i = -pad ; i <= pad ; ++i) { *outPixel += gaussWindow[pad+i]*windowCenter[i]; } *outPixel /= windowSum; } } // blur in Y; now filling in the actual desired destination. We have to do // the transpose again; these transposes guarantee that we read memory in // linear order. for (int y = 0 ; y < tmpHeight ; ++y) { float *srcScanline = tmpImage + y*tmpWidth; for (int x = pad ; x < tmpWidth - pad ; ++x) { float *windowCenter = srcScanline + x; float finalValue = 0; for (int i = -pad ; i <= pad ; ++i) { finalValue += gaussWindow[pad+i]*windowCenter[i]; } finalValue /= windowSum; uint8_t *outPixel = dstPixels + (x-pad)*dstWidth + y; // transposed output int integerPixel = int(finalValue + 0.5f); *outPixel = SkClampMax( SkClampPos(integerPixel), 255 ); } } dst->fImage = dstPixels; // if need be, alloc the "real" dst (same size as src) and copy/merge // the blur into it (applying the src) if (style == kInner_Style) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = src.computeImageSize(); if (0 == srcSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(srcSize); merge_src_with_blur(dst->fImage, src.fRowBytes, srcPixels, src.fRowBytes, dstPixels + pad*dst->fRowBytes + pad, dst->fRowBytes, srcWidth, srcHeight); SkMask::FreeImage(dstPixels); } else if (style != kNormal_Style) { clamp_with_orig(dstPixels + pad*dst->fRowBytes + pad, dst->fRowBytes, srcPixels, src.fRowBytes, srcWidth, srcHeight, style); } (void)autoCall.detach(); } if (style == kInner_Style) { dst->fBounds = src.fBounds; // restore trimmed bounds dst->fRowBytes = src.fRowBytes; } return true; }
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style style, Quality quality, SkIPoint* margin) { if (src.fFormat != SkMask::kA8_Format) { return false; } // Force high quality off for small radii (performance) if (radius < SkIntToScalar(3)) { quality = kLow_Quality; } // highQuality: use three box blur passes as a cheap way // to approximate a Gaussian blur int passCount = (kHigh_Quality == quality) ? 3 : 1; SkScalar passRadius = (kHigh_Quality == quality) ? SkScalarMul( radius, kBlurRadiusFudgeFactor): radius; int rx = SkScalarCeil(passRadius); int outerWeight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255); SkASSERT(rx >= 0); SkASSERT((unsigned)outerWeight <= 255); if (rx <= 0) { return false; } int ry = rx; // only do square blur for now int padx = passCount * rx; int pady = passCount * ry; if (margin) { margin->set(padx, pady); } dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady, src.fBounds.fRight + padx, src.fBounds.fBottom + pady); dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = NULL; if (src.fImage) { size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } int sw = src.fBounds.width(); int sh = src.fBounds.height(); const uint8_t* sp = src.fImage; uint8_t* dp = SkMask::AllocImage(dstSize); SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp); // build the blurry destination SkAutoTMalloc<uint8_t> tmpBuffer(dstSize); uint8_t* tp = tmpBuffer.get(); int w = sw, h = sh; if (outerWeight == 255) { int loRadius, hiRadius; get_adjusted_radii(passRadius, &loRadius, &hiRadius); if (kHigh_Quality == quality) { // Do three X blurs, with a transpose on the final one. w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h, false); w = boxBlur(tp, w, dp, hiRadius, loRadius, w, h, false); w = boxBlur(dp, w, tp, hiRadius, hiRadius, w, h, true); // Do three Y blurs, with a transpose on the final one. h = boxBlur(tp, h, dp, loRadius, hiRadius, h, w, false); h = boxBlur(dp, h, tp, hiRadius, loRadius, h, w, false); h = boxBlur(tp, h, dp, hiRadius, hiRadius, h, w, true); } else { w = boxBlur(sp, src.fRowBytes, tp, rx, rx, w, h, true); h = boxBlur(tp, h, dp, ry, ry, h, w, true); } } else { if (kHigh_Quality == quality) { // Do three X blurs, with a transpose on the final one. w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, false, outerWeight); w = boxBlurInterp(tp, w, dp, rx, w, h, false, outerWeight); w = boxBlurInterp(dp, w, tp, rx, w, h, true, outerWeight); // Do three Y blurs, with a transpose on the final one. h = boxBlurInterp(tp, h, dp, ry, h, w, false, outerWeight); h = boxBlurInterp(dp, h, tp, ry, h, w, false, outerWeight); h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWeight); } else { w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWeight); h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWeight); } } dst->fImage = dp; // if need be, alloc the "real" dst (same size as src) and copy/merge // the blur into it (applying the src) if (style == kInner_Style) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = src.computeImageSize(); if (0 == srcSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(srcSize); merge_src_with_blur(dst->fImage, src.fRowBytes, sp, src.fRowBytes, dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sw, sh); SkMask::FreeImage(dp); } else if (style != kNormal_Style) { clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sp, src.fRowBytes, sw, sh, style); } (void)autoCall.detach(); } if (style == kInner_Style) { dst->fBounds = src.fBounds; // restore trimmed bounds dst->fRowBytes = src.fRowBytes; } return true; }
SkRTree::Branch SkRTree::bulkLoad(SkTDArray<Branch>* branches, int level) { if (branches->count() == 1) { // Only one branch: it will be the root Branch out = (*branches)[0]; branches->rewind(); return out; } else { // We sort the whole list by y coordinates, if we are told to do so. // // We expect Webkit / Blink to give us a reasonable x,y order. // Avoiding this call resulted in a 17% win for recording with // negligible difference in playback speed. if (fSortWhenBulkLoading) { SkTQSort(branches->begin(), branches->end() - 1, RectLessY()); } int numBranches = branches->count() / fMaxChildren; int remainder = branches->count() % fMaxChildren; int newBranches = 0; if (0 != remainder) { ++numBranches; // If the remainder isn't enough to fill a node, we'll need to add fewer nodes to // some other branches to make up for it if (remainder >= fMinChildren) { remainder = 0; } else { remainder = fMinChildren - remainder; } } int numStrips = SkScalarCeil(SkScalarSqrt(SkIntToScalar(numBranches) * SkScalarInvert(fAspectRatio))); int numTiles = SkScalarCeil(SkIntToScalar(numBranches) / SkIntToScalar(numStrips)); int currentBranch = 0; for (int i = 0; i < numStrips; ++i) { // Once again, if we are told to do so, we sort by x. if (fSortWhenBulkLoading) { int begin = currentBranch; int end = currentBranch + numTiles * fMaxChildren - SkMin32(remainder, (fMaxChildren - fMinChildren) * numTiles); if (end > branches->count()) { end = branches->count(); } // Now we sort horizontal strips of rectangles by their x coords SkTQSort(branches->begin() + begin, branches->begin() + end - 1, RectLessX()); } for (int j = 0; j < numTiles && currentBranch < branches->count(); ++j) { int incrementBy = fMaxChildren; if (remainder != 0) { // if need be, omit some nodes to make up for remainder if (remainder <= fMaxChildren - fMinChildren) { incrementBy -= remainder; remainder = 0; } else { incrementBy = fMinChildren; remainder -= fMaxChildren - fMinChildren; } } Node* n = allocateNode(level); n->fNumChildren = 1; *n->child(0) = (*branches)[currentBranch]; Branch b; b.fBounds = (*branches)[currentBranch].fBounds; b.fChild.subtree = n; ++currentBranch; for (int k = 1; k < incrementBy && currentBranch < branches->count(); ++k) { b.fBounds.join((*branches)[currentBranch].fBounds); *n->child(k) = (*branches)[currentBranch]; ++n->fNumChildren; ++currentBranch; } (*branches)[newBranches] = b; ++newBranches; } } branches->setCount(newBranches); return this->bulkLoad(branches, level + 1); } }
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style style, Quality quality, SkIPoint* margin) { if (src.fFormat != SkMask::kA8_Format) { return false; } // Force high quality off for small radii (performance) if (radius < SkIntToScalar(3)) quality = kLow_Quality; // highQuality: use three box blur passes as a cheap way to approximate a Gaussian blur int passCount = (quality == kHigh_Quality) ? 3 : 1; SkScalar passRadius = SkScalarDiv(radius, SkScalarSqrt(SkIntToScalar(passCount))); int rx = SkScalarCeil(passRadius); int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255); SkASSERT(rx >= 0); SkASSERT((unsigned)outer_weight <= 255); if (rx <= 0) { return false; } int ry = rx; // only do square blur for now int padx = passCount * rx; int pady = passCount * ry; if (margin) { margin->set(padx, pady); } dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady, src.fBounds.fRight + padx, src.fBounds.fBottom + pady); dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = NULL; if (src.fImage) { size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } int sw = src.fBounds.width(); int sh = src.fBounds.height(); const uint8_t* sp = src.fImage; uint8_t* dp = SkMask::AllocImage(dstSize); SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp); // build the blurry destination { const size_t storageW = sw + 2 * (passCount - 1) * rx + 1; const size_t storageH = sh + 2 * (passCount - 1) * ry + 1; SkAutoTMalloc<uint32_t> storage(storageW * storageH); uint32_t* sumBuffer = storage.get(); //pass1: sp is source, dp is destination build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes); if (outer_weight == 255) { apply_kernel(dp, rx, ry, sumBuffer, sw, sh); } else { apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight); } if (quality == kHigh_Quality) { //pass2: dp is source, tmpBuffer is destination int tmp_sw = sw + 2 * rx; int tmp_sh = sh + 2 * ry; SkAutoTMalloc<uint8_t> tmpBuffer(dstSize); build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, dp, tmp_sw); if (outer_weight == 255) apply_kernel(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh); else apply_kernel_interp(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh, outer_weight); //pass3: tmpBuffer is source, dp is destination tmp_sw += 2 * rx; tmp_sh += 2 * ry; build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, tmpBuffer.get(), tmp_sw); if (outer_weight == 255) apply_kernel(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh); else apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh, outer_weight); } } dst->fImage = dp; // if need be, alloc the "real" dst (same size as src) and copy/merge // the blur into it (applying the src) if (style == kInner_Style) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = src.computeImageSize(); if (0 == srcSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(srcSize); merge_src_with_blur(dst->fImage, src.fRowBytes, sp, src.fRowBytes, dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sw, sh); SkMask::FreeImage(dp); } else if (style != kNormal_Style) { clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sp, src.fRowBytes, sw, sh, style); } (void)autoCall.detach(); } if (style == kInner_Style) { dst->fBounds = src.fBounds; // restore trimmed bounds dst->fRowBytes = src.fRowBytes; } return true; }
void SkWindow::forceInvalAll() { fDirtyRgn.setRect(0, 0, SkScalarCeil(this->width()), SkScalarCeil(this->height())); }
bool MCGBlurBox(const SkMask& p_src, SkScalar p_x_radius, SkScalar p_y_radius, SkScalar p_x_spread, SkScalar p_y_spread, SkMask& r_dst) { int t_pass_count; t_pass_count = 3; // Maximum amount of spread is 254 pixels. int x_spread, y_spread; x_spread = SkMin32(SkScalarFloor(p_x_radius * p_x_spread), 254); y_spread = SkMin32(SkScalarFloor(p_y_radius * p_y_spread), 254); p_x_radius -= x_spread; p_y_radius -= y_spread; int rx, ry; rx = SkScalarCeil(p_x_radius); ry = SkScalarCeil(p_y_radius); SkScalar px, py; px = rx; py = ry; int wx, wy; wx = 255 - SkScalarRound((SkIntToScalar(rx) - px) * 255); wy = 255 - SkScalarRound((SkIntToScalar(ry) - py) * 255); int t_pad_x, t_pad_y; t_pad_x = rx + x_spread; t_pad_y = ry + y_spread; r_dst . fBounds . set(p_src . fBounds . fLeft - t_pad_x, p_src . fBounds . fTop - t_pad_y, p_src . fBounds . fRight + t_pad_x, p_src . fBounds . fBottom + t_pad_y); r_dst . fRowBytes = r_dst . fBounds . width(); r_dst . fFormat = SkMask::kA8_Format; r_dst . fImage = NULL; if (p_src . fImage == NULL) return true; size_t t_dst_size; t_dst_size = r_dst . computeImageSize(); if (t_dst_size == 0) return false; int sw, sh; sw = p_src . fBounds . width(); sh = p_src . fBounds . height(); const uint8_t *sp; sp = p_src . fImage; uint8_t *dp; dp = SkMask::AllocImage(t_dst_size); if (dp == nil) return false; uint8_t *tp; tp = SkMask::AllocImage(t_dst_size); if (tp == nil) { SkMask::FreeImage(dp); return false; } int w, h; w = sw; h = sh; if (wx == 255) { if (t_pass_count == 3) { int r; r = rx; bool t_has_spread; t_has_spread = false; if (x_spread != 0 || y_spread != 0) { //w = dilateMask(sp, p_src . fRowBytes, tp, x_spread, w, h, true); //h = dilateMask(tp, h, dp, y_spread, h, w, true); dilateDistanceXY(sp, dp, x_spread, y_spread, w, h, w, h); t_has_spread = true; } int trx; trx = (r + 2) / 3; r -= trx; int rx_lo, rx_hi; rx_lo = rx_hi = trx; w = boxBlur(t_has_spread ? dp : sp, t_has_spread ? w : p_src . fRowBytes, tp, rx_lo, rx_hi, w, h, false); trx = (r + 1) / 2; r -= trx; rx_lo = rx_hi = trx; w = boxBlur(tp, w, dp, rx_hi, rx_lo, w, h, false); trx = r; rx_lo = rx_hi = trx; w = boxBlur(dp, w, tp, rx_hi, rx_hi, w, h, true); } else w = boxBlur(sp, p_src . fRowBytes, tp, rx, rx, w, h, true); } else { if (t_pass_count == 3) { int r; r = rx; bool t_has_spread; t_has_spread = false; if (x_spread != 0 || y_spread != 0) { //w = dilateMask(sp, p_src . fRowBytes, tp, x_spread, w, h, true); //h = dilateMask(tp, h, dp, y_spread, h, w, true); dilateDistanceXY(sp, dp, x_spread, y_spread, w, h, w, h); t_has_spread = true; } int trx; trx = (r + 2) / 3; r -= trx; w = boxBlurInterp(t_has_spread ? dp : sp, t_has_spread ? w : p_src . fRowBytes, tp, trx, w, h, false, wx); trx = (r + 1) / 2; r -= trx; w = boxBlurInterp(tp, w, dp, trx, w, h, false, wx); trx = r; w = boxBlurInterp(dp, w, tp, trx, w, h, true, wx); } else w = boxBlurInterp(sp, p_src . fRowBytes, tp, rx, w, h, true, wx); } if (wy == 255) { if (t_pass_count == 3) { int r; r = ry; int sry; sry = (r + 2) / 3; r -= sry; int ry_lo, ry_hi; ry_lo = ry_hi = sry; h = boxBlur(tp, h, dp, ry_lo, ry_hi, h, w, false); sry = (r + 1) / 2; r -= sry; ry_lo = ry_hi = sry; h = boxBlur(dp, h, tp, ry_hi, ry_lo, h, w, false); sry = r; ry_lo = ry_hi = sry; h = boxBlur(tp, h, dp, ry_hi, ry_hi, h, w, true); } else h = boxBlur(tp, h, dp, ry, ry, h, w, true); } else { if (t_pass_count == 3) { int r; r = ry; int sry; sry = (r + 2) / 3; r -= sry; h = boxBlurInterp(tp, h, dp, sry, h, w, false, wy); sry = (r + 1) / 2; r -= sry; h = boxBlurInterp(dp, h, tp, sry, h, w, false, wy); sry = r; h = boxBlurInterp(tp, h, dp, sry, h, w, true, wy); } else w = boxBlurInterp(tp, h, dp, rx, h, w, true, wy); } SkMask::FreeImage(tp); r_dst . fImage = dp; return true; }