예제 #1
0
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;
}
예제 #2
0
// 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]);
        }
    }
}
예제 #3
0
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);
}
예제 #4
0
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;
}
예제 #6
0
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;
    }
}
예제 #8
0
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;
}
예제 #10
0
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;
}
예제 #11
0
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;
}
예제 #12
0
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;
}
예제 #13
0
    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;
    }
예제 #14
0
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;
}
예제 #15
0
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;
}
예제 #18
0
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);
    }
}
예제 #19
0
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;
}
예제 #20
0
void SkWindow::forceInvalAll() {
    fDirtyRgn.setRect(0, 0,
                      SkScalarCeil(this->width()),
                      SkScalarCeil(this->height()));
}
예제 #21
0
파일: blur.cpp 프로젝트: alilloyd/livecode
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;
}