// missingImage, textAreaResizeCorner PassRefPtr<Image> Image::loadPlatformResource(const char *name) { android::AssetManager* am = globalAssetManager(); SkString path("webkit/"); path.append(name); path.append(".png"); android::Asset* a = am->open(path.c_str(), android::Asset::ACCESS_BUFFER); if (a == NULL) { SkDebugf("---------------- failed to open image asset %s\n", name); return NULL; } SkAutoTDelete<android::Asset> ad(a); SkBitmap bm; if (SkImageDecoder::DecodeMemory(a->getBuffer(false), a->getLength(), &bm)) { SkBitmapRef* ref = new SkBitmapRef(bm); // create will call ref(), so we need aur() to release ours upon return SkAutoUnref aur(ref); return BitmapImage::create(ref, 0); } return Image::nullImage(); }
virtual void onDraw(SkCanvas* canvas) { this->drawBG(canvas); SkMatrix saveM = *fMatrixRefs[3]; SkScalar c = SkIntToScalar(50); fMatrixRefs[3]->preRotate(SkIntToScalar(30), c, c); SkMatrix matrix; SkGroupShape* gs = new SkGroupShape; SkAutoUnref aur(gs); gs->appendShape(&fGroup); matrix.setScale(-SK_Scalar1, SK_Scalar1); matrix.postTranslate(SkIntToScalar(220), SkIntToScalar(240)); gs->appendShape(&fGroup, matrix); matrix.setTranslate(SkIntToScalar(240), 0); matrix.preScale(SK_Scalar1*2, SK_Scalar1*2); gs->appendShape(&fGroup, matrix); #if 0 canvas->drawShape(gs); #else SkPicture pict; SkCanvas* cv = pict.beginRecording(1000, 1000); cv->scale(SK_ScalarHalf, SK_ScalarHalf); cv->drawShape(gs); cv->translate(SkIntToScalar(680), SkIntToScalar(480)); cv->scale(-SK_Scalar1, SK_Scalar1); cv->drawShape(gs); pict.endRecording(); canvas->drawPicture(pict); #endif *fMatrixRefs[3] = saveM; }
virtual void onDraw(SkCanvas* canvas) { this->drawBG(canvas); SkMatrix matrix; SkGroupShape* gs = new SkGroupShape; SkAutoUnref aur(gs); gs->appendShape(&fGroup); matrix.setScale(-SK_Scalar1, SK_Scalar1); matrix.postTranslate(SkIntToScalar(220), SkIntToScalar(240)); gs->appendShape(&fGroup, matrix); matrix.setTranslate(SkIntToScalar(240), 0); matrix.preScale(SK_Scalar1*2, SK_Scalar1*2); gs->appendShape(&fGroup, matrix); #if 1 SkPicture* pict = new SkPicture; SkCanvas* cv = pict->beginRecording(1000, 1000); cv->scale(SK_ScalarHalf, SK_ScalarHalf); gs->draw(cv); cv->translate(SkIntToScalar(680), SkIntToScalar(480)); cv->scale(-SK_Scalar1, SK_Scalar1); gs->draw(cv); pict->endRecording(); canvas->drawPicture(*pict); pict->unref(); #endif }
DEF_TEST(ColorFilter, reporter) { SkRandom rand; for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) { SkColor color = rand.nextU(); // ensure we always get a filter, by avoiding the possibility of a // special case that would return NULL (if color's alpha is 0 or 0xFF) color = SkColorSetA(color, 0x7F); SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, (SkXfermode::Mode)mode); // allow for no filter if we're in Dst mode (its a no op) if (SkXfermode::kDst_Mode == mode && NULL == cf) { continue; } SkAutoUnref aur(cf); REPORTER_ASSERT(reporter, cf); SkColor c = ~color; SkXfermode::Mode m = ILLEGAL_MODE; SkColor expectedColor = color; SkXfermode::Mode expectedMode = (SkXfermode::Mode)mode; // SkDebugf("--- mc [%d %x] ", mode, color); REPORTER_ASSERT(reporter, cf->asColorMode(&c, &m)); // handle special-case folding by the factory if (SkXfermode::kClear_Mode == mode) { if (c != expectedColor) { expectedColor = 0; } if (m != expectedMode) { expectedMode = SkXfermode::kSrc_Mode; } } // SkDebugf("--- got [%d %x] expected [%d %x]\n", m, c, expectedMode, expectedColor); REPORTER_ASSERT(reporter, c == expectedColor); REPORTER_ASSERT(reporter, m == expectedMode); { SkColorFilter* cf2 = reincarnate_colorfilter(cf); SkAutoUnref aur2(cf2); REPORTER_ASSERT(reporter, cf2); SkColor c2 = ~color; SkXfermode::Mode m2 = ILLEGAL_MODE; REPORTER_ASSERT(reporter, cf2->asColorMode(&c2, &m2)); REPORTER_ASSERT(reporter, c2 == expectedColor); REPORTER_ASSERT(reporter, m2 == expectedMode); } } test_composecolorfilter_limit(reporter); }
// Return the context associated with the next logical typeface, or NULL if // there are no more entries in the fallback chain. SkScalerContext* SkScalerContext::allocNextContext() const { #ifdef SK_BUILD_FOR_ANDROID SkTypeface* newFace = SkAndroidNextLogicalTypeface(fRec.fFontID, fRec.fOrigFontID, fPaintOptionsAndroid); if (0 == newFace) { return NULL; } SkAutoTUnref<SkTypeface> aur(newFace); uint32_t newFontID = newFace->uniqueID(); SkOrderedWriteBuffer androidBuffer(128); fPaintOptionsAndroid.flatten(androidBuffer); SkAutoDescriptor ad(sizeof(fRec) + androidBuffer.size() + SkDescriptor::ComputeOverhead(2)); SkDescriptor* desc = ad.getDesc(); desc->init(); SkScalerContext::Rec* newRec = (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, sizeof(fRec), &fRec); androidBuffer.writeToMemory(desc->addEntry(kAndroidOpts_SkDescriptorTag, androidBuffer.size(), NULL)); newRec->fFontID = newFontID; desc->computeChecksum(); return newFace->createScalerContext(desc); #else return NULL; #endif }
// CAPPFIX_WEB_WOFF FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer, bool woffEnabled) { RefPtr<SharedBuffer> sfntBuffer; if (woffEnabled && isWOFF(buffer)) { Vector<char> sfnt; if (!convertWOFFToSfnt(buffer, sfnt)) return 0; sfntBuffer = SharedBuffer::adoptVector(sfnt); buffer = sfntBuffer.get(); } // pass true until we know how we can share the data, and not have to // make a copy of it. SkStream* stream = new SkMemoryStream(buffer->data(), buffer->size(), true); SkTypeface* face = SkTypeface::CreateFromStream(stream); // Release the stream. stream->unref(); if (0 == face) { SkDebugf("--------- SkTypeface::CreateFromBuffer failed %d\n", buffer->size()); return NULL; } SkAutoUnref aur(face); return new FontCustomPlatformData(face); }
static void TestBitmapHeap(skiatest::Reporter* reporter) { // Create a bitmap shader. SkBitmap bm; bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); bm.allocPixels(); bm.eraseColor(SK_ColorRED); uint32_t* pixel = bm.getAddr32(1,0); *pixel = SK_ColorBLUE; SkShader* bitmapShader = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkAutoTUnref<SkShader> aur(bitmapShader); // Flatten, storing it in the bitmap heap. SkBitmapHeap heap(1, 1); SkChunkFlatController controller(1024); controller.setBitmapStorage(&heap); FlatDictionary dictionary(&controller); // Dictionary and heap start off empty. REPORTER_ASSERT(reporter, heap.count() == 0); REPORTER_ASSERT(reporter, dictionary.count() == 0); heap.deferAddingOwners(); int index = dictionary.find(*bitmapShader); heap.endAddingOwnersDeferral(true); // The dictionary and heap should now each have one entry. REPORTER_ASSERT(reporter, 1 == index); REPORTER_ASSERT(reporter, heap.count() == 1); REPORTER_ASSERT(reporter, dictionary.count() == 1); // The bitmap entry's refcount should be 1, then 0 after release. SkBitmapHeapEntry* entry = heap.getEntry(0); REPORTER_ASSERT(reporter, SkBitmapHeapTester::GetRefCount(entry) == 1); entry->releaseRef(); REPORTER_ASSERT(reporter, SkBitmapHeapTester::GetRefCount(entry) == 0); // Now clear out the heap, after which it should be empty. heap.freeMemoryIfPossible(~0U); REPORTER_ASSERT(reporter, heap.count() == 0); // Now attempt to flatten the shader again. heap.deferAddingOwners(); index = dictionary.find(*bitmapShader); heap.endAddingOwnersDeferral(false); // The dictionary should report the same index since the new entry is identical. // The bitmap heap should contain the bitmap, but with no references. REPORTER_ASSERT(reporter, 1 == index); REPORTER_ASSERT(reporter, heap.count() == 1); REPORTER_ASSERT(reporter, SkBitmapHeapTester::GetRefCount(heap.getEntry(0)) == 0); }
static SkBitmap load_bitmap() { SkStream* stream = new SkFILEStream("/skimages/sesame_street_ensemble-hp.jpg"); SkAutoUnref aur(stream); SkBitmap bm; if (SkImageDecoder::DecodeStream(stream, &bm, SkBitmap::kNo_Config, SkImageDecoder::kDecodeBounds_Mode)) { SkPixelRef* pr = new SkImageRef_GlobalPool(stream, bm.config(), 1); bm.setPixelRef(pr)->unref(); } return bm; }
BitmapGlue* BitmapFactoryGlue::decodeByteArray(const NativeArray<uint8_t>& data, int offset, int length, Options& options) { /* If optionsShareable() we could decide to just wrap the java array and share it, but that means adding a globalref to the java array object and managing its lifetime. For now we just always copy the array's data if optionsPurgeable(), unless we're just decoding bounds. */ bool purgeable = options.isPurgeable && !options.justDecodeBounds; SkStream* stream = new SkMemoryStream(data.ptr(offset,length), length, purgeable); SkAutoUnref aur(stream); return doDecode(stream, options, purgeable); }
void paintSkiaText(GraphicsContext* context, HFONT hfont, int numGlyphs, const WORD* glyphs, const int* advances, const GOFFSET* offsets, const SkPoint* origin) { int size; int quality; SkTypeface* face = CreateTypefaceFromHFont(hfont, &size, &quality); SkAutoUnref aur(face); paintSkiaText(context, hfont, face, size, quality, numGlyphs, glyphs, advances, offsets, origin); }
void paintSkiaText(GraphicsContext* context, HFONT hfont, int numGlyphs, const WORD* glyphs, const int* advances, const GOFFSET* offsets, const SkPoint& origin, const SkRect& textRect) { int size; int paintTextFlags; SkTypeface* face = CreateTypefaceFromHFont(hfont, &size, &paintTextFlags); SkAutoUnref aur(face); paintSkiaText(context, hfont, face, size, paintTextFlags, numGlyphs, glyphs, advances, offsets, origin, textRect); }
virtual void onDrawContent(SkCanvas* canvas) { drawSomething(canvas); SkPicture* pict = new SkPicture; SkAutoUnref aur(pict); drawSomething(pict->beginRecording(100, 100)); pict->endRecording(); canvas->save(); canvas->translate(SkIntToScalar(300), SkIntToScalar(50)); canvas->scale(-SK_Scalar1, -SK_Scalar1); canvas->translate(-SkIntToScalar(100), -SkIntToScalar(50)); canvas->drawPicture(*pict); canvas->restore(); canvas->save(); canvas->translate(SkIntToScalar(200), SkIntToScalar(150)); canvas->scale(SK_Scalar1, -SK_Scalar1); canvas->translate(0, -SkIntToScalar(50)); canvas->drawPicture(*pict); canvas->restore(); canvas->save(); canvas->translate(SkIntToScalar(100), SkIntToScalar(100)); canvas->scale(-SK_Scalar1, SK_Scalar1); canvas->translate(-SkIntToScalar(100), 0); canvas->drawPicture(*pict); canvas->restore(); #ifdef SK_DEVELOPER if (false) { SkDebugfDumper dumper; SkDumpCanvas dumpCanvas(&dumper); dumpCanvas.drawPicture(*pict); } #endif // test that we can re-record a subpicture, and see the results SkMWCRandom rand(SampleCode::GetAnimTime()); canvas->translate(SkIntToScalar(10), SkIntToScalar(250)); drawCircle(fSubPicture->beginRecording(50, 50), 25, rand.nextU() | 0xFF000000); canvas->drawPicture(*fPicture); delayInval(500); }
virtual void onDrawContent(SkCanvas* canvas) { SkScalar angle = SampleCode::GetAnimScalar(SkIntToScalar(180), SkIntToScalar(360)); SkMatrix saveM = *fMatrixRefs[3]; SkScalar c = SkIntToScalar(50); fMatrixRefs[3]->preRotate(angle, c, c); const SkScalar dx = 350; const SkScalar dy = 500; const int N = 1; for (int v = -N; v <= N; v++) { for (int h = -N; h <= N; h++) { SkAutoCanvasRestore acr(canvas, true); canvas->translate(h * dx, v * dy); SkMatrix matrix; SkGroupShape* gs = new SkGroupShape; SkAutoUnref aur(gs); gs->appendShape(&fGroup); matrix.setScale(-SK_Scalar1, SK_Scalar1); matrix.postTranslate(SkIntToScalar(220), SkIntToScalar(240)); gs->appendShape(&fGroup, matrix); matrix.setTranslate(SkIntToScalar(240), 0); matrix.preScale(SK_Scalar1*2, SK_Scalar1*2); gs->appendShape(&fGroup, matrix); #if 1 SkPicture* pict = new SkPicture; SkCanvas* cv = pict->beginRecording(1000, 1000); cv->scale(SK_ScalarHalf, SK_ScalarHalf); gs->draw(cv); cv->translate(SkIntToScalar(680), SkIntToScalar(480)); cv->scale(-SK_Scalar1, SK_Scalar1); gs->draw(cv); pict->endRecording(); drawpicture(canvas, *pict); pict->unref(); #endif }} *fMatrixRefs[3] = saveM; this->inval(NULL); }
FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { // pass true until we know how we can share the data, and not have to // make a copy of it. SkStream* stream = new SkMemoryStream(buffer->data(), buffer->size(), true); SkTypeface* face = SkTypeface::CreateFromStream(stream); // Release the stream. stream->unref(); if (0 == face) { SkDebugf("--------- SkTypeface::CreateFromBuffer failed %d\n", buffer->size()); return NULL; } SkAutoUnref aur(face); return new FontCustomPlatformData(face); }
BitmapGlue* BitmapFactoryGlue::nativeDecodeAsset(Asset& asset, SkIRect padding, Options& options) { SkStream* stream; bool forcePurgeable = options.isPurgeable; if (forcePurgeable) { // if we could "ref/reopen" the asset, we may not need to copy it here // and we could assume optionsShareable, since assets are always RO stream = copyAssetToStream(asset); if (NULL == stream) { return NULL; } } else { // since we know we'll be done with the asset when we return, we can // just use a simple wrapper stream = new AssetStreamAdaptor(asset); } SkAutoUnref aur(stream); return doDecode(stream, options, true, forcePurgeable); }
static void Tests(skiatest::Reporter* reporter) { // Test flattening SkShader SkPoint points[2]; points[0].set(0, 0); points[1].set(SkIntToScalar(20), SkIntToScalar(20)); SkColor colors[2]; colors[0] = SK_ColorRED; colors[1] = SK_ColorBLUE; SkShader* shader = SkGradientShader::CreateLinear(points, colors, NULL, 2, SkShader::kRepeat_TileMode); SkAutoUnref aur(shader); testCreate(reporter, shader, flattenFlattenableProc); // Test SkBitmap { SkBitmap bm; bm.setConfig(SkBitmap::kARGB_8888_Config, 50, 50); bm.allocPixels(); SkCanvas canvas(bm); SkPaint paint; paint.setShader(shader); canvas.drawPaint(paint); testCreate(reporter, &bm, &SkFlattenObjectProc<SkBitmap>); } // Test SkColorFilter SkColorFilter* cf = SkColorFilter::CreateLightingFilter(SK_ColorBLUE, SK_ColorRED); SkAutoUnref aurcf(cf); testCreate(reporter, cf, &flattenFlattenableProc); // Test SkXfermode SkXfermode* xfer = SkXfermode::Create(SkXfermode::kDstOver_Mode); SkAutoUnref aurxf(xfer); testCreate(reporter, xfer, &flattenFlattenableProc); }
static int fileline( scm *scmp, scmcon *conp, FILE *s) { char ptr[1024]; char *valu; char c; int done = 0; int sta = 0; for (done = 0; !done;) { if (fgets(ptr, 1023, s) == NULL) break; char *cp; for (cp = ptr; *cp >= ' '; cp++); *cp = 0; // trim off CR/LF LOG(LOG_DEBUG, "Sockline: %s", ptr); c = ptr[0]; if (!isspace((int)(unsigned char)(ptr[1]))) { LOG(LOG_ERR, "Invalid line: ignored"); continue; } valu = afterwhite(ptr + 1); switch (c) { case 'b': /* begin */ case 'B': LOG(LOG_INFO, "AUR beginning at %s", valu); break; case 'e': case 'E': /* end */ LOG(LOG_INFO, "AUR ending at %s", valu); done = 1; break; case 'c': case 'C': /* cd */ if (hdir != NULL) { free((void *)hdir); hdir = NULL; } hdir = strdup(valu); break; case 'a': case 'A': /* add */ LOG(LOG_INFO, "AUR add request: %s", valu); sta = aur(scmp, conp, 'a', valu); if (sta < 0) LOG(LOG_ERR, "Status was %d (%s)", sta, err2string(sta)); else LOG(LOG_DEBUG, "Status was %d", sta); break; case 'u': case 'U': /* update */ LOG(LOG_INFO, "AUR update request: %s", valu); sta = aur(scmp, conp, 'u', valu); if (sta < 0) LOG(LOG_ERR, "Status was %d (%s)", sta, err2string(sta)); else LOG(LOG_DEBUG, "Status was %d", sta); break; case 'r': case 'R': /* remove */ LOG(LOG_INFO, "AUR remove request: %s", valu); sta = aur(scmp, conp, 'r', valu); if (sta < 0) LOG(LOG_ERR, "Status was %d (%s)", sta, err2string(sta)); else LOG(LOG_DEBUG, "Status was %d", sta); break; case 'l': case 'L': /* link */ LOG(LOG_INFO, "AUR link request: %s", valu); break; case 'f': case 'F': /* fatal error */ LOG(LOG_ERR, "AUR fatal error: %s", valu); done = -1; break; case 'x': case 'X': /* error */ LOG(LOG_ERR, "AUR error: %s", valu); break; case 'w': case 'W': /* warning */ LOG(LOG_WARNING, "AUR warning: %s", valu); break; case 'i': case 'I': /* information */ LOG(LOG_INFO, "AUR message: %s", valu); break; case 's': case 'S': /* save */ (void)saveState(conp, scmp); break; case 'v': case 'V': /* restore */ (void)restoreState(conp, scmp); break; case 'y': case 'Y': /* synchronize */ break; case 0: break; default: LOG(LOG_INFO, "AUR invalid tag '%c' ignored", c); break; } } return (sta); }
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, SkBitmap::Config prefConfig, Mode mode) { // SkAutoTrace apr("SkPNGImageDecoder::onDecode"); /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, NULL); // png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { return false; } /* Allocate/initialize the memory for image information. */ png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return false; } PNGAutoClean autoClean(png_ptr, info_ptr); /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { return false; } /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); /* where user_io_ptr is a structure you want available to the callbacks */ /* If we have already read some of the signature */ // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); // hookup our peeker so we can see any user-chunks the caller may be interested in png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); if (this->getPeeker()) { png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); } /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); png_uint_32 origWidth, origHeight; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); SkBitmap::Config config; bool hasAlpha = false; bool doDither = this->getDitherImage(); // check for sBIT chunk data, in case we should disable dithering because // our data is not truely 8bits per component if (doDither) { #if 0 SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red, info_ptr->sig_bit.green, info_ptr->sig_bit.blue, info_ptr->sig_bit.alpha); #endif // 0 seems to indicate no information available if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) && pos_le(info_ptr->sig_bit.green, SK_G16_BITS) && pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) { doDither = false; } } if (color_type == PNG_COLOR_TYPE_PALETTE) { config = SkBitmap::kIndex8_Config; // defer sniffing for hasAlpha } else { png_color_16p transColor; png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &transColor); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || PNG_COLOR_TYPE_RGB_ALPHA == color_type || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { hasAlpha = true; config = SkBitmap::kARGB_8888_Config; } else { // we get to choose the config config = prefConfig; if (config == SkBitmap::kNo_Config) { config = SkImageDecoder::GetDeviceConfig(); } if (config != SkBitmap::kRGB_565_Config && config != SkBitmap::kARGB_4444_Config) { config = SkBitmap::kARGB_8888_Config; } } } if (!this->chooseFromOneChoice(config, origWidth, origHeight)) { return false; } const int sampleSize = this->getSampleSize(); SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } // from here down we are concerned with colortables and pixels /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (bit_depth == 16) { png_set_strip_16(png_ptr); } /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ if (bit_depth < 8) { png_set_packing(png_ptr); } /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_gray_1_2_4_to_8(png_ptr); } /* Make a grayscale image into RGB. */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we // draw lots faster if we can flag the bitmap has being opaque bool reallyHasAlpha = false; SkColorTable* colorTable = NULL; if (color_type == PNG_COLOR_TYPE_PALETTE) { int num_palette; png_colorp palette; png_bytep trans; int num_trans; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); /* BUGGY IMAGE WORKAROUND We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count which is a problem since we use the byte as an index. To work around this we grow the colortable by 1 (if its < 256) and duplicate the last color into that slot. */ int colorCount = num_palette + (num_palette < 256); colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); SkPMColor* colorPtr = colorTable->lockColors(); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); hasAlpha = (num_trans > 0); } else { num_trans = 0; colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); } // check for bad images that might make us crash if (num_trans > num_palette) { num_trans = num_palette; } int index = 0; int transLessThanFF = 0; for (; index < num_trans; index++) { transLessThanFF |= (int)*trans - 0xFF; *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue); palette++; } reallyHasAlpha |= (transLessThanFF < 0); for (; index < num_palette; index++) { *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); palette++; } // see BUGGY IMAGE WORKAROUND comment above if (num_palette < 256) { *colorPtr = colorPtr[-1]; } colorTable->unlockColors(true); } SkAutoUnref aur(colorTable); if (!this->allocPixelRef(decodedBitmap, colorTable)) { delete colorTable; return false; } SkAutoLockPixels alp(*decodedBitmap); /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ // if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) // ; // png_set_swap_alpha(png_ptr); /* swap bytes of 16 bit files to least significant byte first */ // png_set_swap(png_ptr); /* Add filler (or alpha) byte (before/after each RGB triplet) */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } /* Turn on interlace handling. REQUIRED if you are not using * png_read_image(). To see how to handle interlacing passes, * see the png_read_row() method below: */ const int number_passes = interlace_type != PNG_INTERLACE_NONE ? png_set_interlace_handling(png_ptr) : 1; /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (ie you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { for (int i = 0; i < number_passes; i++) { for (png_uint_32 y = 0; y < origHeight; y++) { uint8_t* bmRow = decodedBitmap->getAddr8(0, y); png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); } } } else { SkScaledBitmapSampler::SrcConfig sc; int srcBytesPerPixel = 4; if (SkBitmap::kIndex8_Config == config) { sc = SkScaledBitmapSampler::kIndex; srcBytesPerPixel = 1; } else if (hasAlpha) { sc = SkScaledBitmapSampler::kRGBA; } else { sc = SkScaledBitmapSampler::kRGBX; } SkAutoMalloc storage(origWidth * srcBytesPerPixel); const int height = decodedBitmap->height(); for (int i = 0; i < number_passes; i++) { if (!sampler.begin(decodedBitmap, sc, doDither)) { return false; } uint8_t* srcRow = (uint8_t*)storage.get(); skip_src_rows(png_ptr, srcRow, sampler.srcY0()); for (int y = 0; y < height; y++) { uint8_t* tmp = srcRow; png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); reallyHasAlpha |= sampler.next(srcRow); if (y < height - 1) { skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); } } // skip the rest of the rows (if any) png_uint_32 read = (height - 1) * sampler.srcDY() + sampler.srcY0() + 1; SkASSERT(read <= origHeight); skip_src_rows(png_ptr, srcRow, origHeight - read); } if (hasAlpha && !reallyHasAlpha) { SkDEBUGF(("Image doesn't really have alpha [%d %d]\n", origWidth, origHeight)); } } /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); decodedBitmap->setIsOpaque(!reallyHasAlpha); return true; }
static SkImageFilter* make2() { SkColorFilter* cf = SkColorFilter::CreateModeFilter(SK_ColorBLUE, SkXfermode::kSrcIn_Mode); SkAutoUnref aur(cf); return SkColorFilterImageFilter::Create(cf); }
// Stripped down version of TestBitmapCopy that checks basic fields (width, height, config, genID) // to ensure that they were copied properly. static void TestGpuBitmapCopy(skiatest::Reporter* reporter, GrContextFactory* factory) { #ifdef SK_BUILD_FOR_ANDROID // https://code.google.com/p/skia/issues/detail?id=753 return; #endif for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) { GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type); if (!GrContextFactory::IsRenderingGLContext(glType)) { continue; } GrContext* grContext = factory->get(glType); if (NULL == grContext) { continue; } if (NULL == grContext) { return; } static const Pair gPairs[] = { { SkBitmap::kNo_Config, "000" }, { SkBitmap::kARGB_4444_Config, "011" }, { SkBitmap::kARGB_8888_Config, "011" }, }; const int W = 20; const int H = 33; for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { SkBitmap src, dst; SkGpuDevice* device = SkNEW_ARGS(SkGpuDevice, (grContext, gPairs[i].fConfig, W, H)); SkAutoUnref aur(device); src = device->accessBitmap(false); device->clear(SK_ColorWHITE); // Draw something different to the same portion of the bitmap that we will extract as a // subset, so that comparing the pixels of the subset will be meaningful. SkIRect subsetRect = SkIRect::MakeLTRB(W/2, H/2, W, H); SkCanvas drawingCanvas(device); SkPaint paint; paint.setColor(SK_ColorRED); drawingCanvas.drawRect(SkRect::MakeFromIRect(subsetRect), paint); // Extract a subset. If this succeeds we will test copying the subset. SkBitmap subset; const bool extracted = src.extractSubset(&subset, subsetRect); for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) { dst.reset(); bool success = src.deepCopyTo(&dst, gPairs[j].fConfig); bool expected = gPairs[i].fValid[j] != '0'; if (success != expected) { SkString str; str.printf("SkBitmap::deepCopyTo from %s to %s. expected %s returned %s", gConfigName[i], gConfigName[j], boolStr(expected), boolStr(success)); reporter->reportFailed(str); } bool canSucceed = src.canCopyTo(gPairs[j].fConfig); if (success != canSucceed) { SkString str; str.printf("SkBitmap::deepCopyTo from %s to %s returned %s," "but canCopyTo returned %s", gConfigName[i], gConfigName[j], boolStr(success), boolStr(canSucceed)); reporter->reportFailed(str); } TestIndividualCopy(reporter, gPairs[j].fConfig, success, src, dst); // Test copying the subset bitmap, using both copyTo and deepCopyTo. if (extracted) { SkBitmap subsetCopy; success = subset.copyTo(&subsetCopy, gPairs[j].fConfig); REPORTER_ASSERT(reporter, success == expected); REPORTER_ASSERT(reporter, success == canSucceed); TestIndividualCopy(reporter, gPairs[j].fConfig, success, subset, subsetCopy, false); // Reset the bitmap so that a failed copyTo will leave it in the expected state. subsetCopy.reset(); success = subset.deepCopyTo(&subsetCopy, gPairs[j].fConfig); REPORTER_ASSERT(reporter, success == expected); REPORTER_ASSERT(reporter, success == canSucceed); TestIndividualCopy(reporter, gPairs[j].fConfig, success, subset, subsetCopy, true); } } // for (size_t j = ... } // for (size_t i = ... } // GrContextFactory::GLContextType }
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, Mode mode) { png_structp png_ptr; png_infop info_ptr; if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) { return false; } if (setjmp(png_jmpbuf(png_ptr))) { return false; } PNGAutoClean autoClean(png_ptr, info_ptr); png_uint_32 origWidth, origHeight; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); SkBitmap::Config config; bool hasAlpha = false; bool doDither = this->getDitherImage(); SkPMColor theTranspColor = 0; // 0 tells us not to try to match if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theTranspColor) == false) { return false; } const int sampleSize = this->getSampleSize(); SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } // from here down we are concerned with colortables and pixels // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we // draw lots faster if we can flag the bitmap has being opaque bool reallyHasAlpha = false; SkColorTable* colorTable = NULL; if (color_type == PNG_COLOR_TYPE_PALETTE) { decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable); } SkAutoUnref aur(colorTable); if (!this->allocPixelRef(decodedBitmap, SkBitmap::kIndex8_Config == config ? colorTable : NULL)) { return false; } SkAutoLockPixels alp(*decodedBitmap); /* Add filler (or alpha) byte (before/after each RGB triplet) */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } /* Turn on interlace handling. REQUIRED if you are not using * png_read_image(). To see how to handle interlacing passes, * see the png_read_row() method below: */ const int number_passes = interlace_type != PNG_INTERLACE_NONE ? png_set_interlace_handling(png_ptr) : 1; /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (ie you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { for (int i = 0; i < number_passes; i++) { for (png_uint_32 y = 0; y < origHeight; y++) { uint8_t* bmRow = decodedBitmap->getAddr8(0, y); png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); } } } else { SkScaledBitmapSampler::SrcConfig sc; int srcBytesPerPixel = 4; if (colorTable != NULL) { sc = SkScaledBitmapSampler::kIndex; srcBytesPerPixel = 1; } else if (hasAlpha) { sc = SkScaledBitmapSampler::kRGBA; } else { sc = SkScaledBitmapSampler::kRGBX; } /* We have to pass the colortable explicitly, since we may have one even if our decodedBitmap doesn't, due to the request that we upscale png's palette to a direct model */ SkAutoLockColors ctLock(colorTable); if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { return false; } const int height = decodedBitmap->height(); if (number_passes > 1) { SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); uint8_t* base = (uint8_t*)storage.get(); size_t rb = origWidth * srcBytesPerPixel; for (int i = 0; i < number_passes; i++) { uint8_t* row = base; for (png_uint_32 y = 0; y < origHeight; y++) { uint8_t* bmRow = row; png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); row += rb; } } // now sample it base += sampler.srcY0() * rb; for (int y = 0; y < height; y++) { reallyHasAlpha |= sampler.next(base); base += sampler.srcDY() * rb; } } else { SkAutoMalloc storage(origWidth * srcBytesPerPixel); uint8_t* srcRow = (uint8_t*)storage.get(); skip_src_rows(png_ptr, srcRow, sampler.srcY0()); for (int y = 0; y < height; y++) { uint8_t* tmp = srcRow; png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); reallyHasAlpha |= sampler.next(srcRow); if (y < height - 1) { skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); } } // skip the rest of the rows (if any) png_uint_32 read = (height - 1) * sampler.srcDY() + sampler.srcY0() + 1; SkASSERT(read <= origHeight); skip_src_rows(png_ptr, srcRow, origHeight - read); } } /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); if (0 != theTranspColor) { reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); } decodedBitmap->setIsOpaque(!reallyHasAlpha); return true; }
void GraphicsContext::setPlatformShadow(const FloatSize& size, float blurFloat, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; // Detect when there's no effective shadow and clear the looper. if (!size.width() && !size.height() && !blurFloat) { platformContext()->setDrawLooper(0); return; } double width = size.width(); double height = size.height(); double blur = blurFloat; uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag; SkXfermode::Mode colorMode = SkXfermode::kSrc_Mode; if (m_state.shadowsIgnoreTransforms) { // Currently only the GraphicsContext associated with the // CanvasRenderingContext for HTMLCanvasElement have shadows ignore // Transforms. So with this flag set, we know this state is associated // with a CanvasRenderingContext. mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag; // CSS wants us to ignore the original's alpha, but Canvas wants us to // modulate with it. Using shadowsIgnoreTransforms to tell us that we're // in a Canvas, we change the colormode to kDst_Mode, so we don't overwrite // it with our layer's (default opaque-black) color. colorMode = SkXfermode::kDst_Mode; // CG uses natural orientation for Y axis, but the HTML5 canvas spec // does not. // So we now flip the height since it was flipped in // CanvasRenderingContext in order to work with CG. height = -height; } SkColor c; if (color.isValid()) c = color.rgb(); else c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" apple shadow color. // TODO(tc): Should we have a max value for the blur? CG clamps at 1000.0 // for perf reasons. SkLayerDrawLooper* dl = new SkLayerDrawLooper; SkAutoUnref aur(dl); // top layer, we just draw unchanged dl->addLayer(); // lower layer contains our offset, blur, and colorfilter SkLayerDrawLooper::LayerInfo info; info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; // our blur info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; info.fColorMode = colorMode; info.fOffset.set(width, height); info.fPostTranslate = m_state.shadowsIgnoreTransforms; SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags); SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode); SkPaint* paint = dl->addLayer(info); SkSafeUnref(paint->setMaskFilter(mf)); SkSafeUnref(paint->setColorFilter(cf)); // dl is now built, just install it platformContext()->setDrawLooper(dl); }
virtual void onDrawContent(SkCanvas* canvas) { canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); if (false) { SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(50); paint.setTypeface(SkTypeface::CreateFromName("Arial Unicode MS", SkTypeface::kNormal)); SkSafeUnref(paint.getTypeface()); char buffer[10]; size_t len = SkUTF8_FromUnichar(0x8500, buffer); canvas->drawText(buffer, len, 40, 40, paint); return; } if (false) { SkPaint paint; paint.setAntiAlias(true); SkRect r0 = { 0, 0, 10.5f, 20 }; SkRect r1 = { 10.5f, 10, 20, 30 }; paint.setColor(SK_ColorRED); canvas->drawRect(r0, paint); paint.setColor(SK_ColorBLUE); canvas->drawRect(r1, paint); return; } const struct { SkXfermode::Mode fMode; const char* fLabel; } gModes[] = { { SkXfermode::kClear_Mode, "Clear" }, { SkXfermode::kSrc_Mode, "Src" }, { SkXfermode::kDst_Mode, "Dst" }, { SkXfermode::kSrcOver_Mode, "SrcOver" }, { SkXfermode::kDstOver_Mode, "DstOver" }, { SkXfermode::kSrcIn_Mode, "SrcIn" }, { SkXfermode::kDstIn_Mode, "DstIn" }, { SkXfermode::kSrcOut_Mode, "SrcOut" }, { SkXfermode::kDstOut_Mode, "DstOut" }, { SkXfermode::kSrcATop_Mode, "SrcATop" }, { SkXfermode::kDstATop_Mode, "DstATop" }, { SkXfermode::kXor_Mode, "Xor" }, { SkXfermode::kPlus_Mode, "Plus" }, /*{ SkXfermode::kModulate_Mode, "Modulate" }, { SkXfermode::kScreen_Mode, "Screen" }, { SkXfermode::kOverlay_Mode, "Overlay" }, { SkXfermode::kDarken_Mode, "Darken" }, { SkXfermode::kLighten_Mode, "Lighten" }, { SkXfermode::kColorDodge_Mode, "ColorDodge" }, { SkXfermode::kColorBurn_Mode, "ColorBurn" }, { SkXfermode::kHardLight_Mode, "HardLight" }, { SkXfermode::kSoftLight_Mode, "SoftLight" }, { SkXfermode::kDifference_Mode, "Difference" }, { SkXfermode::kExclusion_Mode, "Exclusion" },*/ }; const SkScalar w = SkIntToScalar(W); const SkScalar h = SkIntToScalar(H); SkShader* s = SkShader::CreateBitmapShader(fBG, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix m; m.setScale(SkIntToScalar(6), SkIntToScalar(6)); s->setLocalMatrix(m); SkPaint labelP; labelP.setAntiAlias(true); labelP.setLCDRenderText(true); labelP.setTextAlign(SkPaint::kCenter_Align); setNamedTypeface(&labelP, "Menlo Regular"); const int W = 5; SkScalar x0 = 0; for (int twice = 0; twice < 2; twice++) { SkScalar x = x0, y = 0; for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) { SkXfermode* mode = SkXfermode::Create(gModes[i].fMode); SkAutoUnref aur(mode); SkRect r; r.set(x, y, x+w, y+h); SkPaint p; p.setStyle(SkPaint::kFill_Style); p.setShader(s); canvas->drawRect(r, p); canvas->saveLayer(&r, NULL); draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop); canvas->restore(); r.inset(-SK_ScalarHalf, -SK_ScalarHalf); p.setStyle(SkPaint::kStroke_Style); p.setShader(NULL); canvas->drawRect(r, p); canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel), x + w/2, y - labelP.getTextSize()/2, labelP); x += w + SkIntToScalar(10); if ((i % W) == W - 1) { x = x0; y += h + SkIntToScalar(30); } } x0 += SkIntToScalar(400); } s->unref(); }
void onDraw(SkCanvas* canvas) override { canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); const struct { SkXfermode::Mode fMode; const char* fLabel; int fSourceTypeMask; // The source types to use this // mode with. See draw_mode for // an explanation of each type. // PDF has to play some tricks // to support the base modes, // test those more extensively. } gModes[] = { { SkXfermode::kClear_Mode, "Clear", kAll_SrcType }, { SkXfermode::kSrc_Mode, "Src", kAll_SrcType }, { SkXfermode::kDst_Mode, "Dst", kAll_SrcType }, { SkXfermode::kSrcOver_Mode, "SrcOver", kAll_SrcType }, { SkXfermode::kDstOver_Mode, "DstOver", kAll_SrcType }, { SkXfermode::kSrcIn_Mode, "SrcIn", kAll_SrcType }, { SkXfermode::kDstIn_Mode, "DstIn", kAll_SrcType }, { SkXfermode::kSrcOut_Mode, "SrcOut", kAll_SrcType }, { SkXfermode::kDstOut_Mode, "DstOut", kAll_SrcType }, { SkXfermode::kSrcATop_Mode, "SrcATop", kAll_SrcType }, { SkXfermode::kDstATop_Mode, "DstATop", kAll_SrcType }, { SkXfermode::kXor_Mode, "Xor", kBasic_SrcType }, { SkXfermode::kPlus_Mode, "Plus", kBasic_SrcType }, { SkXfermode::kModulate_Mode, "Modulate", kAll_SrcType }, { SkXfermode::kScreen_Mode, "Screen", kBasic_SrcType }, { SkXfermode::kOverlay_Mode, "Overlay", kBasic_SrcType }, { SkXfermode::kDarken_Mode, "Darken", kBasic_SrcType }, { SkXfermode::kLighten_Mode, "Lighten", kBasic_SrcType }, { SkXfermode::kColorDodge_Mode, "ColorDodge", kBasic_SrcType }, { SkXfermode::kColorBurn_Mode, "ColorBurn", kBasic_SrcType }, { SkXfermode::kHardLight_Mode, "HardLight", kBasic_SrcType }, { SkXfermode::kSoftLight_Mode, "SoftLight", kBasic_SrcType }, { SkXfermode::kDifference_Mode, "Difference", kBasic_SrcType }, { SkXfermode::kExclusion_Mode, "Exclusion", kBasic_SrcType }, { SkXfermode::kMultiply_Mode, "Multiply", kAll_SrcType }, { SkXfermode::kHue_Mode, "Hue", kBasic_SrcType }, { SkXfermode::kSaturation_Mode, "Saturation", kBasic_SrcType }, { SkXfermode::kColor_Mode, "Color", kBasic_SrcType }, { SkXfermode::kLuminosity_Mode, "Luminosity", kBasic_SrcType }, }; const SkScalar w = SkIntToScalar(W); const SkScalar h = SkIntToScalar(H); SkMatrix m; m.setScale(SkIntToScalar(6), SkIntToScalar(6)); SkShader* s = SkShader::CreateBitmapShader(fBG, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &m); SkPaint labelP; labelP.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&labelP); labelP.setTextAlign(SkPaint::kCenter_Align); const int W = 5; SkScalar x0 = 0; SkScalar y0 = 0; for (int sourceType = 1; sourceType & kAll_SrcType; sourceType <<= 1) { SkScalar x = x0, y = y0; for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) { if ((gModes[i].fSourceTypeMask & sourceType) == 0) { continue; } SkXfermode* mode = SkXfermode::Create(gModes[i].fMode); SkAutoUnref aur(mode); SkRect r; r.set(x, y, x+w, y+h); SkPaint p; p.setStyle(SkPaint::kFill_Style); p.setShader(s); canvas->drawRect(r, p); canvas->saveLayer(&r, NULL); draw_mode(canvas, mode, static_cast<SrcType>(sourceType), r.fLeft, r.fTop); canvas->restore(); r.inset(-SK_ScalarHalf, -SK_ScalarHalf); p.setStyle(SkPaint::kStroke_Style); p.setShader(NULL); canvas->drawRect(r, p); #if 1 canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel), x + w/2, y - labelP.getTextSize()/2, labelP); #endif x += w + SkIntToScalar(10); if ((i % W) == W - 1) { x = x0; y += h + SkIntToScalar(30); } } if (y < 320) { if (x > x0) { y += h + SkIntToScalar(30); } y0 = y; } else { x0 += SkIntToScalar(400); y0 = 0; } } s->unref(); }
virtual void onDraw(SkCanvas* canvas) { canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); this->drawBG(canvas); const struct { SkXfermode::Mode fMode; const char* fLabel; } gModes[] = { { SkXfermode::kClear_Mode, "Clear" }, { SkXfermode::kSrc_Mode, "Src" }, { SkXfermode::kDst_Mode, "Dst" }, { SkXfermode::kSrcOver_Mode, "SrcOver" }, { SkXfermode::kDstOver_Mode, "DstOver" }, { SkXfermode::kSrcIn_Mode, "SrcIn" }, { SkXfermode::kDstIn_Mode, "DstIn" }, { SkXfermode::kSrcOut_Mode, "SrcOut" }, { SkXfermode::kDstOut_Mode, "DstOut" }, { SkXfermode::kSrcATop_Mode, "SrcATop" }, { SkXfermode::kDstATop_Mode, "DstATop" }, { SkXfermode::kXor_Mode, "Xor" }, { SkXfermode::kPlus_Mode, "Plus" }, { SkXfermode::kMultiply_Mode, "Multiply" }, { SkXfermode::kScreen_Mode, "Screen" }, { SkXfermode::kOverlay_Mode, "Overlay" }, { SkXfermode::kDarken_Mode, "Darken" }, { SkXfermode::kLighten_Mode, "Lighten" }, { SkXfermode::kColorDodge_Mode, "ColorDodge" }, { SkXfermode::kColorBurn_Mode, "ColorBurn" }, { SkXfermode::kHardLight_Mode, "HardLight" }, { SkXfermode::kSoftLight_Mode, "SoftLight" }, { SkXfermode::kDifference_Mode, "Difference" }, { SkXfermode::kExclusion_Mode, "Exclusion" }, }; const SkScalar w = SkIntToScalar(W); const SkScalar h = SkIntToScalar(H); SkShader* s = SkShader::CreateBitmapShader(fBG, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix m; m.setScale(SkIntToScalar(6), SkIntToScalar(6)); s->setLocalMatrix(m); SkPaint labelP; labelP.setAntiAlias(true); labelP.setTextAlign(SkPaint::kCenter_Align); const int W = 5; SkScalar x0 = 0; for (int twice = 0; twice < 2; twice++) { SkScalar x = x0, y = 0; for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) { SkXfermode* mode = SkXfermode::Create(gModes[i].fMode); SkAutoUnref aur(mode); SkRect r; r.set(x, y, x+w, y+h); SkPaint p; p.setStyle(SkPaint::kFill_Style); p.setShader(s); canvas->drawRect(r, p); canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag); draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop); canvas->restore(); r.inset(-SK_ScalarHalf, -SK_ScalarHalf); p.setStyle(SkPaint::kStroke_Style); p.setShader(NULL); canvas->drawRect(r, p); #if 1 canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel), x + w/2, y - labelP.getTextSize()/2, labelP); #endif x += w + SkIntToScalar(10); if ((i % W) == W - 1) { x = x0; y += h + SkIntToScalar(30); } } x0 += SkIntToScalar(400); } s->unref(); }