SkFlattenable* SkMatrixConvolutionImageFilter::CreateProc(SkReadBuffer& buffer) {
    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
    SkISize kernelSize;
    kernelSize.fWidth = buffer.readInt();
    kernelSize.fHeight = buffer.readInt();
    const int count = buffer.getArrayCount();

    const int64_t kernelArea = sk_64_mul(kernelSize.width(), kernelSize.height());
    if (!buffer.validate(kernelArea == count)) {
        return nullptr;
    }
    SkAutoSTArray<16, SkScalar> kernel(count);
    if (!buffer.readScalarArray(kernel.get(), count)) {
        return nullptr;
    }
    SkScalar gain = buffer.readScalar();
    SkScalar bias = buffer.readScalar();
    SkIPoint kernelOffset;
    kernelOffset.fX = buffer.readInt();
    kernelOffset.fY = buffer.readInt();
    TileMode tileMode = (TileMode)buffer.readInt();
    bool convolveAlpha = buffer.readBool();
    return Create(kernelSize, kernel.get(), gain, bias, kernelOffset, tileMode, convolveAlpha,
                  common.getInput(0), &common.cropRect());
}
Beispiel #2
0
/** returns the product if it is positive and fits in 31 bits. Otherwise this
    returns 0.
 */
static int32_t safeMul32(int32_t a, int32_t b) {
    int64_t size = sk_64_mul(a, b);
    if (size > 0 && sk_64_isS32(size)) {
        return sk_64_asS32(size);
    }
    return 0;
}
Beispiel #3
0
size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) {
    if (levelCount < 0) {
        return 0;
    }
    int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize;
    if (!SkTFitsIn<int32_t>(size)) {
        return 0;
    }
    return SkTo<int32_t>(size);
}
Beispiel #4
0
bool SkRgnBuilder::init(int maxHeight, int maxTransitions, bool pathIsInverse) {
    if ((maxHeight | maxTransitions) < 0) {
        return false;
    }

    if (pathIsInverse) {
        // allow for additional X transitions to "invert" each scanline
        // [ L' ... normal transitions ... R' ]
        //
        maxTransitions += 2;
    }

    // compute the count with +1 and +3 slop for the working buffer
    int64_t count = sk_64_mul(maxHeight + 1, 3 + maxTransitions);

    if (pathIsInverse) {
        // allow for two "empty" rows for the top and bottom
        //      [ Y, 1, L, R, S] == 5 (*2 for top and bottom)
        count += 10;
    }

    if (count < 0 || !sk_64_isS32(count)) {
        return false;
    }
    fStorageCount = sk_64_asS32(count);

    int64_t size = sk_64_mul(fStorageCount, sizeof(SkRegion::RunType));
    if (size < 0 || !sk_64_isS32(size)) {
        return false;
    }

    fStorage = (SkRegion::RunType*)sk_malloc_flags(sk_64_asS32(size), 0);
    if (NULL == fStorage) {
        return false;
    }

    fCurrScanline = NULL;    // signal empty collection
    fPrevScanline = NULL;    // signal first scanline
    return true;
}
Beispiel #5
0
bool SkValidatingReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
    const uint32_t count = this->getArrayCount();
    this->validate(size == count);
    (void)this->skip(sizeof(uint32_t)); // Skip array count
    const uint64_t byteLength64 = sk_64_mul(count, elementSize);
    const size_t byteLength = count * elementSize;
    this->validate(byteLength == byteLength64);
    const void* ptr = this->skip(SkAlign4(byteLength));
    if (!fError) {
        memcpy(value, ptr, byteLength);
        return true;
    }
    return false;
}
Beispiel #6
0
bool SkSurface_Raster::Valid(const SkImageInfo& info, size_t rowBytes) {
    if (info.isEmpty()) {
        return false;
    }

    static const size_t kMaxTotalSize = SK_MaxS32;

    int shift = 0;
    switch (info.colorType()) {
        case kAlpha_8_SkColorType:
            shift = 0;
            break;
        case kRGB_565_SkColorType:
            shift = 1;
            break;
        case kN32_SkColorType:
            shift = 2;
            break;
        case kRGBA_F16_SkColorType:
            shift = 3;
            break;
        default:
            return false;
    }

    if (kIgnoreRowBytesValue == rowBytes) {
        return true;
    }

    uint64_t minRB = (uint64_t)info.width() << shift;
    if (minRB > rowBytes) {
        return false;
    }

    size_t alignedRowBytes = rowBytes >> shift << shift;
    if (alignedRowBytes != rowBytes) {
        return false;
    }

    uint64_t size = sk_64_mul(info.height(), rowBytes);
    if (size > kMaxTotalSize) {
        return false;
    }

    return true;
}
SkMatrixConvolutionImageFilter::SkMatrixConvolutionImageFilter(const SkISize& kernelSize,
                                                               const SkScalar* kernel,
                                                               SkScalar gain,
                                                               SkScalar bias,
                                                               const SkIPoint& kernelOffset,
                                                               TileMode tileMode,
                                                               bool convolveAlpha,
                                                               sk_sp<SkImageFilter> input,
                                                               const CropRect* cropRect)
    : INHERITED(&input, 1, cropRect)
    , fKernelSize(kernelSize)
    , fGain(gain)
    , fBias(bias)
    , fKernelOffset(kernelOffset)
    , fTileMode(tileMode)
    , fConvolveAlpha(convolveAlpha) {
    size_t size = (size_t) sk_64_mul(fKernelSize.width(), fKernelSize.height());
    fKernel = new SkScalar[size];
    memcpy(fKernel, kernel, size * sizeof(SkScalar));
    SkASSERT(kernelSize.fWidth >= 1 && kernelSize.fHeight >= 1);
    SkASSERT(kernelOffset.fX >= 0 && kernelOffset.fX < kernelSize.fWidth);
    SkASSERT(kernelOffset.fY >= 0 && kernelOffset.fY < kernelSize.fHeight);
}
Beispiel #8
0
bool BGRAConvolve2D(const unsigned char* sourceData,
                    int sourceByteRowStride,
                    bool sourceHasAlpha,
                    const SkConvolutionFilter1D& filterX,
                    const SkConvolutionFilter1D& filterY,
                    int outputByteRowStride,
                    unsigned char* output) {

    int maxYFilterSize = filterY.maxFilter();

    // The next row in the input that we will generate a horizontally
    // convolved row for. If the filter doesn't start at the beginning of the
    // image (this is the case when we are only resizing a subset), then we
    // don't want to generate any output rows before that. Compute the starting
    // row for convolution as the first pixel for the first vertical filter.
    int filterOffset, filterLength;
    const SkConvolutionFilter1D::ConvolutionFixed* filterValues =
        filterY.FilterForValue(0, &filterOffset, &filterLength);
    int nextXRow = filterOffset;

    // We loop over each row in the input doing a horizontal convolution. This
    // will result in a horizontally convolved image. We write the results into
    // a circular buffer of convolved rows and do vertical convolution as rows
    // are available. This prevents us from having to store the entire
    // intermediate image and helps cache coherency.
    // We will need four extra rows to allow horizontal convolution could be done
    // simultaneously. We also pad each row in row buffer to be aligned-up to
    // 32 bytes.
    // TODO(jiesun): We do not use aligned load from row buffer in vertical
    // convolution pass yet. Somehow Windows does not like it.
    int rowBufferWidth = (filterX.numValues() + 31) & ~0x1F;
    int rowBufferHeight = maxYFilterSize +
                          (SkOpts::convolve_4_rows_horizontally != nullptr ? 4 : 0);

    // check for too-big allocation requests : crbug.com/528628
    {
        int64_t size = sk_64_mul(rowBufferWidth, rowBufferHeight);
        // need some limit, to avoid over-committing success from malloc, but then
        // crashing when we try to actually use the memory.
        // 100meg seems big enough to allow "normal" zoom factors and image sizes through
        // while avoiding the crash seen by the bug (crbug.com/528628)
        if (size > 100 * 1024 * 1024) {
//            SkDebugf("BGRAConvolve2D: tmp allocation [%lld] too big\n", size);
            return false;
        }
    }

    CircularRowBuffer rowBuffer(rowBufferWidth,
                                rowBufferHeight,
                                filterOffset);

    // Loop over every possible output row, processing just enough horizontal
    // convolutions to run each subsequent vertical convolution.
    SkASSERT(outputByteRowStride >= filterX.numValues() * 4);
    int numOutputRows = filterY.numValues();

    // We need to check which is the last line to convolve before we advance 4
    // lines in one iteration.
    int lastFilterOffset, lastFilterLength;
    filterY.FilterForValue(numOutputRows - 1, &lastFilterOffset,
                           &lastFilterLength);

    for (int outY = 0; outY < numOutputRows; outY++) {
        filterValues = filterY.FilterForValue(outY,
                                              &filterOffset, &filterLength);

        // Generate output rows until we have enough to run the current filter.
        while (nextXRow < filterOffset + filterLength) {
            if (SkOpts::convolve_4_rows_horizontally != nullptr &&
                nextXRow + 3 < lastFilterOffset + lastFilterLength) {
                const unsigned char* src[4];
                unsigned char* outRow[4];
                for (int i = 0; i < 4; ++i) {
                    src[i] = &sourceData[(uint64_t)(nextXRow + i) * sourceByteRowStride];
                    outRow[i] = rowBuffer.advanceRow();
                }
                SkOpts::convolve_4_rows_horizontally(src, filterX, outRow, 4*rowBufferWidth);
                nextXRow += 4;
            } else {
                SkOpts::convolve_horizontally(
                        &sourceData[(uint64_t)nextXRow * sourceByteRowStride],
                        filterX, rowBuffer.advanceRow(), sourceHasAlpha);
                nextXRow++;
            }
        }

        // Compute where in the output image this row of final data will go.
        unsigned char* curOutputRow = &output[(uint64_t)outY * outputByteRowStride];

        // Get the list of rows that the circular buffer has, in order.
        int firstRowInCircularBuffer;
        unsigned char* const* rowsToConvolve =
            rowBuffer.GetRowAddresses(&firstRowInCircularBuffer);

        // Now compute the start of the subset of those rows that the filter needs.
        unsigned char* const* firstRowForFilter =
            &rowsToConvolve[filterOffset - firstRowInCircularBuffer];

        SkOpts::convolve_vertically(filterValues, filterLength,
                                    firstRowForFilter,
                                    filterX.numValues(), curOutputRow,
                                    sourceHasAlpha);
    }
    return true;
}