1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2011 Google Inc.
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBitmapProcShader.h"
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkColorPriv.h"
109ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com#include "SkFlattenableBuffers.h"
11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPixelRef.h"
1229ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com#include "SkErrorInternals.h"
13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    switch (bm.config()) {
16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case SkBitmap::kA8_Config:
17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case SkBitmap::kRGB_565_Config:
18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case SkBitmap::kIndex8_Config:
19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case SkBitmap::kARGB_8888_Config:
20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return true;
22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        default:
23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
26bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
27bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                       TileMode tmx, TileMode tmy) {
30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fRawBitmap = src;
31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fState.fTileModeX = (uint8_t)tmx;
32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fState.fTileModeY = (uint8_t)tmy;
33badeafac94730d6c53098c3d90abc05509ebd6a1reed@android.com    fFlags = 0; // computed in setContext
34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        : INHERITED(buffer) {
389ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.readBitmap(&fRawBitmap);
3960293dcc4d90d75e748eddde055059fc9cb94062reed@google.com    fRawBitmap.setImmutable();
409ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fState.fTileModeX = buffer.readUInt();
419ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fState.fTileModeY = buffer.readUInt();
42badeafac94730d6c53098c3d90abc05509ebd6a1reed@android.com    fFlags = 0; // computed in setContext
43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
45092e2ef83749d3711c0772677502df77a622f75areed@google.comSkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
46092e2ef83749d3711c0772677502df77a622f75areed@google.com                                                   SkMatrix* texM,
47fb2135b20e5c62b084bd64fa6d651f3e4362cd4drileya@google.com                                                   TileMode xy[]) const {
48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (texture) {
49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        *texture = fRawBitmap;
50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (texM) {
52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        texM->reset();
53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (xy) {
55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        xy[0] = (TileMode)fState.fTileModeX;
56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        xy[1] = (TileMode)fState.fTileModeY;
57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
58e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    return kDefault_BitmapType;
59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
61cd2e444e946f5cfec4723f5bc46e9487d82e8e54djsollen@google.comvoid SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->INHERITED::flatten(buffer);
63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
649ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.writeBitmap(fRawBitmap);
659ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.writeUInt(fState.fTileModeX);
669ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.writeUInt(fState.fTileModeY);
67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
699ed8f76ef95fdda704a60a0e787395612bc70443reed@android.comstatic bool only_scale_and_translate(const SkMatrix& matrix) {
709ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
719ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com    return (matrix.getType() & ~mask) == 0;
729ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com}
739ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com
749601a62f74301f2f773240b3b0614e3cb152a024junov@chromium.orgbool SkBitmapProcShader::isOpaque() const {
759601a62f74301f2f773240b3b0614e3cb152a024junov@chromium.org    return fRawBitmap.isOpaque();
769601a62f74301f2f773240b3b0614e3cb152a024junov@chromium.org}
779601a62f74301f2f773240b3b0614e3cb152a024junov@chromium.org
78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkBitmapProcShader::setContext(const SkBitmap& device,
79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                    const SkPaint& paint,
80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                    const SkMatrix& matrix) {
81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // do this first, so we have a correct inverse matrix
82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (!this->INHERITED::setContext(device, paint, matrix)) {
83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return false;
84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fState.fOrigBitmap = fRawBitmap;
87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fState.fOrigBitmap.lockPixels();
88e216b62841acd5db9d91b63960805568259a2e0ereed@android.com    if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fState.fOrigBitmap.unlockPixels();
90d65131b413804c06fe7eab7af5205e32ca709332mike@reedtribe.org        this->INHERITED::endContext();
91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return false;
92bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
95bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com        fState.fOrigBitmap.unlockPixels();
96d65131b413804c06fe7eab7af5205e32ca709332mike@reedtribe.org        this->INHERITED::endContext();
97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return false;
98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
99bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
100f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com    const SkBitmap& bitmap = *fState.fBitmap;
101f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com    bool bitmapIsOpaque = bitmap.isOpaque();
102092e2ef83749d3711c0772677502df77a622f75areed@google.com
103bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // update fFlags
104dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com    uint32_t flags = 0;
105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
106dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com        flags |= kOpaqueAlpha_Flag;
107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
109f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com    switch (bitmap.config()) {
110bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case SkBitmap::kRGB_565_Config:
111dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case SkBitmap::kIndex8_Config:
114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case SkBitmap::kARGB_8888_Config:
115bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (bitmapIsOpaque) {
116dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com                flags |= kHasSpan16_Flag;
117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        case SkBitmap::kA8_Config:
120bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;  // never set kHasSpan16_Flag
121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        default:
122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
1249ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com
125f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com    if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
126dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com        // gradients can auto-dither in their 16bit sampler, but we don't so
127f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com        // we clear the flag here.
128dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com        flags &= ~kHasSpan16_Flag;
129dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com    }
130dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com
131bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    // if we're only 1-pixel high, and we don't rotate, then we can claim this
132f4eda68d26c9221e3ccb0de8add5c4e53e054fadreed@android.com    if (1 == bitmap.height() &&
1339ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com            only_scale_and_translate(this->getTotalInverse())) {
13489b7cb1226f0410b0bfda732714571f1876e6aeereed@android.com        flags |= kConstInY32_Flag;
13589b7cb1226f0410b0bfda732714571f1876e6aeereed@android.com        if (flags & kHasSpan16_Flag) {
13689b7cb1226f0410b0bfda732714571f1876e6aeereed@android.com            flags |= kConstInY16_Flag;
13789b7cb1226f0410b0bfda732714571f1876e6aeereed@android.com        }
1389ed8f76ef95fdda704a60a0e787395612bc70443reed@android.com    }
139dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com
140dfd96ac50bb13a4e610ea0923b6554ec3ed96774reed@android.com    fFlags = flags;
141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return true;
142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
143bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
144bd370925b712814b8467a32e31f9d7d921f9f476reed@google.comvoid SkBitmapProcShader::endContext() {
145bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com    fState.fOrigBitmap.unlockPixels();
1466212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com    fState.endContext();
147bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com    this->INHERITED::endContext();
148bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com}
149bd370925b712814b8467a32e31f9d7d921f9f476reed@google.com
150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define BUF_MAX     128
151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
152d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#define TEST_BUFFER_OVERRITEx
153d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com
154d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#ifdef TEST_BUFFER_OVERRITE
155d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com    #define TEST_BUFFER_EXTRA   32
156d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com    #define TEST_PATTERN    0x88888888
157d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#else
158d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com    #define TEST_BUFFER_EXTRA   0
159d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#endif
160d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com
161bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
16213224b7848ecb2753914a5946feab6e503fbf614reed@android.com    const SkBitmapProcState& state = fState;
163ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com    if (state.getShaderProc32()) {
164ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com        state.getShaderProc32()(state, x, y, dstC, count);
16513224b7848ecb2753914a5946feab6e503fbf614reed@android.com        return;
16613224b7848ecb2753914a5946feab6e503fbf614reed@android.com    }
167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
168d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
169ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
170ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
171d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com    int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
172bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
173bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(state.fBitmap->getPixels());
174bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(state.fBitmap->pixelRef() == NULL ||
175e0f5c7da0d07c811789773d1bd555edba3a1cf40reed@google.com             state.fBitmap->pixelRef()->isLocked());
176bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
177bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (;;) {
178bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int n = count;
179bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (n > max) {
180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            n = max;
181bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
182d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com        SkASSERT(n > 0 && n < BUF_MAX*2);
183d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#ifdef TEST_BUFFER_OVERRITE
184d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
185d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com            buffer[BUF_MAX + i] = TEST_PATTERN;
186d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com        }
187d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#endif
188bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        mproc(state, buffer, n, x, y);
189d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#ifdef TEST_BUFFER_OVERRITE
190d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
191d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
192d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com        }
193d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com#endif
194bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        sproc(state, buffer, n, dstC);
195092e2ef83749d3711c0772677502df77a622f75areed@google.com
196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if ((count -= n) == 0) {
197bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
198bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
199d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com        SkASSERT(count > 0);
200bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        x += n;
201bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        dstC += n;
202bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
205f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.comSkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
206f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com    if (fState.getShaderProc32()) {
207f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com        *ctx = &fState;
208f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com        return (ShadeProc)fState.getShaderProc32();
209f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com    }
210f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com    return NULL;
211f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com}
212f1bbd533e266687c5c2b6b406e06ae28bc500920reed@google.com
213bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
21413224b7848ecb2753914a5946feab6e503fbf614reed@android.com    const SkBitmapProcState& state = fState;
215ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com    if (state.getShaderProc16()) {
216ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com        state.getShaderProc16()(state, x, y, dstC, count);
21713224b7848ecb2753914a5946feab6e503fbf614reed@android.com        return;
21813224b7848ecb2753914a5946feab6e503fbf614reed@android.com    }
219092e2ef83749d3711c0772677502df77a622f75areed@google.com
22013224b7848ecb2753914a5946feab6e503fbf614reed@android.com    uint32_t buffer[BUF_MAX];
221ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
222ff37996c5611f53208808d91926aac16d4c9f8aereed@google.com    SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
223cf87e774356ef088b6d221da46a8702d16e19219reed@android.com    int max = fState.maxCountForBufferSize(sizeof(buffer));
224bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(state.fBitmap->getPixels());
226bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(state.fBitmap->pixelRef() == NULL ||
227e0f5c7da0d07c811789773d1bd555edba3a1cf40reed@google.com             state.fBitmap->pixelRef()->isLocked());
228bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
229bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (;;) {
230bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int n = count;
231bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (n > max) {
232bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            n = max;
233bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
234bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        mproc(state, buffer, n, x, y);
235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        sproc(state, buffer, n, dstC);
236092e2ef83749d3711c0772677502df77a622f75areed@google.com
237bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if ((count -= n) == 0) {
238bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            break;
239bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
240bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        x += n;
241bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        dstC += n;
242bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
243bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
244bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
245bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
246bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
24735820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com#include "SkUnPreMultiply.h"
24835820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com#include "SkColorShader.h"
24956dd3b35cc39a66ea2e9e86529dc3c272f3e120creed@google.com#include "SkEmptyShader.h"
25035820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com
25135820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com// returns true and set color if the bitmap can be drawn as a single color
25235820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com// (for efficiency)
25335820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.comstatic bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
25435820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    if (1 != bm.width() || 1 != bm.height()) {
25535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com        return false;
25635820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    }
25735820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com
25835820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    SkAutoLockPixels alp(bm);
25935820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    if (!bm.readyToDraw()) {
26035820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com        return false;
26135820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    }
26235820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com
26335820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    switch (bm.config()) {
26435820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com        case SkBitmap::kARGB_8888_Config:
26535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
26635820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com            return true;
26735820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com        case SkBitmap::kRGB_565_Config:
26835820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
26935820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com            return true;
27035820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com        case SkBitmap::kIndex8_Config:
27135820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
27235820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com            return true;
27335820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com        default: // just skip the other configs for now
27435820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com            break;
27535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    }
27635820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    return false;
27735820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com}
27835820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com
279bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkTemplatesPriv.h"
280bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
28199cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.comstatic bool bitmapIsTooBig(const SkBitmap& bm) {
28299cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
28399cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com    // communicates between its matrix-proc and its sampler-proc. Until we can
28499cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com    // widen that, we have to reject bitmaps that are larger.
28599cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com    //
28699cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com    const int maxSize = 65535;
28799cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com
28899cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com    return bm.width() > maxSize || bm.height() > maxSize;
28999cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com}
29099cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com
291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
292bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                       TileMode tmx, TileMode tmy,
293bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                       void* storage, size_t storageSize) {
294bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkShader* shader;
29535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    SkColor color;
29699cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com    if (src.isNull() || bitmapIsTooBig(src)) {
29756dd3b35cc39a66ea2e9e86529dc3c272f3e120creed@google.com        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
29856dd3b35cc39a66ea2e9e86529dc3c272f3e120creed@google.com    }
29956dd3b35cc39a66ea2e9e86529dc3c272f3e120creed@google.com    else if (canUseColorShader(src, &color)) {
30035820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
30135820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com                              (color));
30235820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    } else {
30335820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
30435820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com                              storageSize, (src, tmx, tmy));
30535820162ea29dccd5b9e7347c84aa943da38f1c7reed@android.com    }
306bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return shader;
307bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
308bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
309bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
310bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
311bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com#ifdef SK_DEVELOPER
312bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.comvoid SkBitmapProcShader::toString(SkString* str) const {
313bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    static const char* gTileModeName[SkShader::kTileModeCount] = {
314bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com        "clamp", "repeat", "mirror"
315bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    };
316092e2ef83749d3711c0772677502df77a622f75areed@google.com
317bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append("BitmapShader: (");
318092e2ef83749d3711c0772677502df77a622f75areed@google.com
319bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->appendf("(%s, %s)",
320bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                 gTileModeName[fState.fTileModeX],
321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                 gTileModeName[fState.fTileModeY]);
322bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
323bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(" ");
324bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    fRawBitmap.toString(str);
325bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
326bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    this->INHERITED::toString(str);
327bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
328bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(")");
329bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
330bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com#endif
331bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
33205614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com///////////////////////////////////////////////////////////////////////////////
33305614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com
33405614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com#if SK_SUPPORT_GPU
33505614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com
33605614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com#include "GrTextureAccess.h"
337c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com#include "effects/GrSimpleTextureEffect.h"
33805614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com#include "SkGr.h"
33905614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com
34038b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.comGrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
34105614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    SkMatrix matrix;
34205614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
34305614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com
34405614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    if (this->hasLocalMatrix()) {
34505614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com        SkMatrix inverse;
34605614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com        if (!this->getLocalMatrix().invert(&inverse)) {
34702c64b785b2a2e18c80c2f27b9a89613bd849791humper@google.com            return NULL;
34805614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com        }
34905614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com        matrix.preConcat(inverse);
35005614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    }
35105614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    SkShader::TileMode tm[] = {
35205614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com        (TileMode)fState.fTileModeX,
35305614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com        (TileMode)fState.fTileModeY,
35405614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    };
35505614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com
35605614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    // Must set wrap and filter on the sampler before requesting a texture.
35729ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com    SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
35829ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com    GrTextureParams::FilterMode textureFilterMode;
35929ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com    switch(paintFilterLevel) {
36029ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com        case SkPaint::kNone_FilterLevel:
36129ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            textureFilterMode = GrTextureParams::kNone_FilterMode;
36229ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            break;
36329ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com        case SkPaint::kLow_FilterLevel:
36429ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            textureFilterMode = GrTextureParams::kBilerp_FilterMode;
36529ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            break;
36629ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com        case SkPaint::kMedium_FilterLevel:
36729ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            textureFilterMode = GrTextureParams::kMipMap_FilterMode;
36829ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            break;
36929ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com        case SkPaint::kHigh_FilterLevel:
37029ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            SkErrorInternals::SetError( kInvalidPaint_SkError,
37129ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com                                        "Sorry, I don't yet support high quality "
37229ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com                                        "filtering on the GPU; falling back to "
37329ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com                                        "MIPMaps.");
37429ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            textureFilterMode = GrTextureParams::kMipMap_FilterMode;
37529ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com            break;
376459084d27d8682c8795548e69087a313b1649385humper@google.com        default:
377459084d27d8682c8795548e69087a313b1649385humper@google.com            SkErrorInternals::SetError( kInvalidPaint_SkError,
378459084d27d8682c8795548e69087a313b1649385humper@google.com                                        "Sorry, I don't understand the filtering "
379459084d27d8682c8795548e69087a313b1649385humper@google.com                                        "mode you asked for.  Falling back to "
380459084d27d8682c8795548e69087a313b1649385humper@google.com                                        "MIPMaps.");
381459084d27d8682c8795548e69087a313b1649385humper@google.com            textureFilterMode = GrTextureParams::kMipMap_FilterMode;
382459084d27d8682c8795548e69087a313b1649385humper@google.com            break;
38337d2c1133a35ca9ef444823d7f1a6a79b3f7871fskia.committer@gmail.com
38429ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com    }
38529ba4805e88962ad40e3ca79c9a768e073f52badhumper@google.com    GrTextureParams params(tm, textureFilterMode);
3868f5dc5a363c2e9548f3b48325a1579a5da92e21absalomon@google.com    GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
38705614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com
38805614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    if (NULL == texture) {
38905614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com        SkDebugf("Couldn't convert bitmap to texture.\n");
39005614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com        return NULL;
39105614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    }
392bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
393c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com    GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params);
3948f5dc5a363c2e9548f3b48325a1579a5da92e21absalomon@google.com    GrUnlockAndUnrefCachedBitmapTexture(texture);
39505614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    return effect;
39605614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com}
39705614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com#endif
398