sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap); }
static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) { SkASSERT(bitmap.getGenerationID() == expectedID); SkASSERT(bitmap.isImmutable()); SkASSERT(bitmap.getPixels()); return true; }
static void test_allocpixels(skiatest::Reporter* reporter) { const int width = 10; const int height = 10; const SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); const size_t explicitRowBytes = info.minRowBytes() + 24; SkBitmap bm; bm.setInfo(info); REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); bm.allocPixels(); REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); bm.reset(); bm.allocPixels(info); REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); bm.setInfo(info, explicitRowBytes); REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes()); bm.allocPixels(); REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes()); bm.reset(); bm.allocPixels(info, explicitRowBytes); REPORTER_ASSERT(reporter, explicitRowBytes == bm.rowBytes()); bm.reset(); bm.setInfo(info, 0); REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); bm.reset(); bm.allocPixels(info, 0); REPORTER_ASSERT(reporter, info.minRowBytes() == bm.rowBytes()); bm.reset(); bool success = bm.setInfo(info, info.minRowBytes() - 1); // invalid for 32bit REPORTER_ASSERT(reporter, !success); REPORTER_ASSERT(reporter, bm.isNull()); }
EXPORT void benchmark(const char* url, int reloadCount, int width, int height) { ScriptController::initializeThreading(); // Setting this allows data: urls to load from a local file. SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForAll); // Create the fake JNIEnv and JavaVM InitializeJavaVM(); // The real function is private to libwebcore but we know what it does. notifyHistoryItemChanged = historyItemChanged; // Implement the shared timer callback MyJavaSharedClient client; JavaSharedClient::SetTimerClient(&client); JavaSharedClient::SetCookieClient(&client); // Create the page with all the various clients ChromeClientAndroid* chrome = new ChromeClientAndroid; EditorClientAndroid* editor = new EditorClientAndroid; DeviceMotionClientAndroid* deviceMotion = new DeviceMotionClientAndroid; DeviceOrientationClientAndroid* deviceOrientation = new DeviceOrientationClientAndroid; WebCore::Page::PageClients pageClients; pageClients.chromeClient = chrome; pageClients.contextMenuClient = new ContextMenuClientAndroid; pageClients.editorClient = editor; pageClients.dragClient = new DragClientAndroid; pageClients.inspectorClient = new InspectorClientAndroid; pageClients.deviceMotionClient = deviceMotion; pageClients.deviceOrientationClient = deviceOrientation; WebCore::Page* page = new WebCore::Page(pageClients); editor->setPage(page); // Create MyWebFrame that intercepts network requests MyWebFrame* webFrame = new MyWebFrame(page); webFrame->setUserAgent("Performance testing"); // needs to be non-empty chrome->setWebFrame(webFrame); // ChromeClientAndroid maintains the reference. Release(webFrame); // Create the Frame and the FrameLoaderClient FrameLoaderClientAndroid* loader = new FrameLoaderClientAndroid(webFrame); RefPtr<Frame> frame = Frame::create(page, NULL, loader); loader->setFrame(frame.get()); // Build our View system, resize it to the given dimensions and release our // references. Note: We keep a referenec to frameView so we can layout and // draw later without risk of it being deleted. WebViewCore* webViewCore = new WebViewCore(JSC::Bindings::getJNIEnv(), MY_JOBJECT, frame.get()); RefPtr<FrameView> frameView = FrameView::create(frame.get()); WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore); frame->setView(frameView); frameView->resize(width, height); Release(webViewCore); Release(webFrameView); // Initialize the frame and turn of low-bandwidth display (it fails an // assertion in the Cache code) frame->init(); frame->selection()->setFocused(true); frame->page()->focusController()->setFocused(true); deviceMotion->setWebViewCore(webViewCore); deviceOrientation->setWebViewCore(webViewCore); // Set all the default settings the Browser normally uses. Settings* s = frame->settings(); #ifdef ANDROID_LAYOUT s->setLayoutAlgorithm(Settings::kLayoutNormal); // Normal layout for now #endif s->setStandardFontFamily("sans-serif"); s->setFixedFontFamily("monospace"); s->setSansSerifFontFamily("sans-serif"); s->setSerifFontFamily("serif"); s->setCursiveFontFamily("cursive"); s->setFantasyFontFamily("fantasy"); s->setMinimumFontSize(8); s->setMinimumLogicalFontSize(8); s->setDefaultFontSize(16); s->setDefaultFixedFontSize(13); s->setLoadsImagesAutomatically(true); s->setJavaScriptEnabled(true); s->setDefaultTextEncodingName("latin1"); s->setPluginsEnabled(false); s->setShrinksStandaloneImagesToFit(false); #ifdef ANDROID_LAYOUT s->setUseWideViewport(false); #endif // Finally, load the actual data ResourceRequest req(url); frame->loader()->load(req, false); do { // Layout the page and service the timer frame->view()->layout(); while (client.m_hasTimer) { client.m_func(); JavaSharedClient::ServiceFunctionPtrQueue(); } JavaSharedClient::ServiceFunctionPtrQueue(); // Layout more if needed. while (frame->view()->needsLayout()) frame->view()->layout(); JavaSharedClient::ServiceFunctionPtrQueue(); if (reloadCount) frame->loader()->reload(true); } while (reloadCount--); // Draw into an offscreen bitmap SkBitmap bmp; bmp.setConfig(SkBitmap::kARGB_8888_Config, width, height); bmp.allocPixels(); SkCanvas canvas(bmp); PlatformGraphicsContext ctx(&canvas); GraphicsContext gc(&ctx); frame->view()->paintContents(&gc, IntRect(0, 0, width, height)); // Write the bitmap to the sdcard SkImageEncoder* enc = SkImageEncoder::Create(SkImageEncoder::kPNG_Type); enc->encodeFile("/sdcard/webcore_test.png", bmp, 100); delete enc; // Tear down the world. frame->loader()->detachFromParent(); delete page; }
PassRefPtr<ImageData> getImageData(const IntRect& rect, const SkBitmap& bitmap, const IntSize& size) { RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); if (bitmap.config() == SkBitmap::kNo_Config) { // This is an empty SkBitmap that could not be configured. ASSERT(!size.width() || !size.height()); return result; } unsigned char* data = result->data()->data()->data(); if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) memset(data, 0, result->data()->length()); int originX = rect.x(); int destX = 0; if (originX < 0) { destX = -originX; originX = 0; } int endX = rect.x() + rect.width(); if (endX > size.width()) endX = size.width(); int numColumns = endX - originX; int originY = rect.y(); int destY = 0; if (originY < 0) { destY = -originY; originY = 0; } int endY = rect.y() + rect.height(); if (endY > size.height()) endY = size.height(); int numRows = endY - originY; ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); SkAutoLockPixels bitmapLock(bitmap); unsigned destBytesPerRow = 4 * rect.width(); unsigned char* destRow = data + destY * destBytesPerRow + destX * 4; for (int y = 0; y < numRows; ++y) { uint32_t* srcRow = bitmap.getAddr32(originX, originY + y); for (int x = 0; x < numColumns; ++x) { unsigned char* destPixel = &destRow[x * 4]; if (multiplied == Unmultiplied) { SkColor color = srcRow[x]; unsigned a = SkColorGetA(color); destPixel[0] = a ? SkColorGetR(color) * 255 / a : 0; destPixel[1] = a ? SkColorGetG(color) * 255 / a : 0; destPixel[2] = a ? SkColorGetB(color) * 255 / a : 0; destPixel[3] = a; } else { // Input and output are both pre-multiplied, we just need to re-arrange the // bytes from the bitmap format to RGBA. destPixel[0] = SkGetPackedR32(srcRow[x]); destPixel[1] = SkGetPackedG32(srcRow[x]); destPixel[2] = SkGetPackedB32(srcRow[x]); destPixel[3] = SkGetPackedA32(srcRow[x]); } } destRow += destBytesPerRow; } return result; }
status_t s3d_camera_test(void) { printf("[Unit Test] SurfaceFlinger 3D display test !\n\n"); sp<SurfaceComposerClient> client; //sp<SurfaceControl> u; //sp<SurfaceControl> c; sp<Surface> s; Surface::SurfaceInfo i; SkBitmap sbs; SkBitmap cam; // ready the png image file if (false == SkImageDecoder::DecodeFile("/data/3D_Camera_SBS.png", &sbs) || false == SkImageDecoder::DecodeFile("/data/camera.png", &cam)) { printf("fail load file"); return INVALID_OPERATION; } // create layer env client = new SurfaceComposerClient(); printf("screen (w, h) = (%d, %d)\n\n", (int)client->getDisplayWidth(0), (int)client->getDisplayHeight(0)); // test set to side by side mode, and pull to topest layer in transaction printf("*** camera test ...\n"); u = client->createSurface(String8("test-ui"), 0, DRAW_FHD_W, DRAW_FHD_H, PIXEL_FORMAT_BGRA_8888); c = client->createSurface(String8("test-camera"), 0, DRAW_FHD_W, DRAW_FHD_H, PIXEL_FORMAT_RGBX_8888); client->openGlobalTransaction(); { u->setLayer(210000); c->setLayer(200000); } client->closeGlobalTransaction(); ANativeWindow *w; // fill camera surface ANativeWindowBuffer *buf; void *ptr; const Rect rect0(544, 960); const Rect rect1(960, 540); s = u->getSurface(); // fill ui surface s->lock(&i); { printf("lock ui, i.s=%d, i.h=%d\n",i.s, i.h); memset(i.bits, 0, i.s * i.h * 4); memcpy(i.bits, cam.getPixels(), 544 * 960 * 4);//buffer stride is bigger then ... } s->unlockAndPost(); s = c->getSurface(); w = s.get(); native_window_api_connect(w, NATIVE_WINDOW_API_CAMERA); native_window_set_buffers_dimensions(w, 960, 540); native_window_set_buffers_format(w, HAL_PIXEL_FORMAT_RGBX_8888); native_window_set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_S3D_TOP_AND_BOTTOM); native_window_set_scaling_mode(w, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); native_window_set_buffers_transform(w, HAL_TRANSFORM_ROT_90); w->dequeueBuffer(w, &buf); GraphicBufferMapper::getInstance().lock(buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, rect1, &ptr); { memcpy(ptr, sbs.getPixels(), 960 * 540 * 4); } GraphicBufferMapper::getInstance().unlock(buf->handle); // inlock to return buffer w->queueBuffer(w, buf); // queue to display uint8_t j = 0x80; client->openGlobalTransaction(); { u->setAlpha(j); } client->closeGlobalTransaction(); sleep(1); client->dispose(); return NO_ERROR; }
static size_t pixel_count(const SkBitmap& bm) { return SkToSizeT(bm.width()) * SkToSizeT(bm.height()); }
static void testBitmapCache_discarded_bitmap(skiatest::Reporter* reporter, SkResourceCache* cache, SkResourceCache::DiscardableFactory factory) { SkBitmap::Allocator* allocator = cache->allocator(); const SkColorType testTypes[] = { kAlpha_8_SkColorType, kRGB_565_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType, kIndex_8_SkColorType, kGray_8_SkColorType }; for (const SkColorType testType : testTypes) { SkBitmap cachedBitmap; make_bitmap(&cachedBitmap, SkImageInfo::Make(5, 5, testType, kPremul_SkAlphaType), allocator); cachedBitmap.setImmutable(); cachedBitmap.unlockPixels(); SkBitmap bm; SkIRect rect = SkIRect::MakeWH(5, 5); // Add a bitmap to the cache. REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.pixelRef(), rect, cachedBitmap, cache)); REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache)); // Finding more than once works fine. REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache)); bm.unlockPixels(); // Drop the pixels in the bitmap. if (factory) { REPORTER_ASSERT(reporter, gPool->getRAMUsed() > 0); gPool->dumpPool(); // The bitmap is not in the cache since it has been dropped. REPORTER_ASSERT(reporter, !SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache)); } make_bitmap(&cachedBitmap, SkImageInfo::Make(5, 5, testType, kPremul_SkAlphaType), allocator); cachedBitmap.setImmutable(); cachedBitmap.unlockPixels(); // We can add the bitmap back to the cache and find it again. REPORTER_ASSERT(reporter, SkBitmapCache::Add(cachedBitmap.pixelRef(), rect, cachedBitmap, cache)); REPORTER_ASSERT(reporter, SkBitmapCache::Find(cachedBitmap.getGenerationID(), rect, &bm, cache)); } test_mipmapcache(reporter, cache); test_bitmap_notify(reporter, cache); test_mipmap_notify(reporter, cache); }
// FIXME: This should be refactored to SkSingleInputImageFilter for // use by other filters. For now, we assume the input is always // premultiplied and unpremultiply it static SkBitmap unpremultiplyBitmap(const SkBitmap& src) { SkAutoLockPixels alp(src); if (!src.getPixels()) { return SkBitmap(); } SkBitmap result; result.setConfig(src.config(), src.width(), src.height()); result.allocPixels(); if (!result.getPixels()) { return SkBitmap(); } for (int y = 0; y < src.height(); ++y) { const uint32_t* srcRow = src.getAddr32(0, y); uint32_t* dstRow = result.getAddr32(0, y); for (int x = 0; x < src.width(); ++x) { dstRow[x] = SkUnPreMultiply::PMColorToColor(srcRow[x]); } } return result; }
SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps) : INHERITED(surfaceProps) , fBitmap(bitmap) { SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); }
/** * Render the SKP file(s) within inputPath, writing their bitmap images into outputDir. * * @param inputPath path to an individual SKP file, or a directory of SKP files * @param outputDir if not NULL, write the image(s) generated into this directory * @param renderer PictureRenderer to use to render the SKPs * @param jsonSummaryPtr if not NULL, add the image(s) generated to this summary */ static bool render_picture(const SkString& inputPath, const SkString* outputDir, sk_tools::PictureRenderer& renderer, sk_tools::ImageResultsSummary *jsonSummaryPtr) { int diffs[256] = {0}; SkBitmap* bitmap = NULL; renderer.setJsonSummaryPtr(jsonSummaryPtr); bool success = render_picture_internal(inputPath, FLAGS_writeWholeImage ? NULL : outputDir, renderer, FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : NULL); if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == NULL)) { SkDebugf("Failed to draw the picture.\n"); SkDELETE(bitmap); return false; } if (FLAGS_validate) { SkBitmap* referenceBitmap = NULL; sk_tools::PictureRenderer* referenceRenderer; // If the renderer uses a BBoxHierarchy, then the reference renderer // will be the same renderer, without the bbh. AutoRestoreBbhType arbbh; if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType != renderer.getBBoxHierarchyType()) { referenceRenderer = &renderer; referenceRenderer->ref(); // to match auto unref below arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHierarchyType); } else { referenceRenderer = SkNEW(sk_tools::SimplePictureRenderer); } SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRenderer); success = render_picture_internal(inputPath, NULL, *referenceRenderer, &referenceBitmap); if (!success || NULL == referenceBitmap || NULL == referenceBitmap->getPixels()) { SkDebugf("Failed to draw the reference picture.\n"); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } if (success && (bitmap->width() != referenceBitmap->width())) { SkDebugf("Expected image width: %i, actual image width %i.\n", referenceBitmap->width(), bitmap->width()); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } if (success && (bitmap->height() != referenceBitmap->height())) { SkDebugf("Expected image height: %i, actual image height %i", referenceBitmap->height(), bitmap->height()); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } for (int y = 0; success && y < bitmap->height(); y++) { for (int x = 0; success && x < bitmap->width(); x++) { int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y), *bitmap->getAddr32(x, y)); SkASSERT(diff >= 0 && diff <= 255); diffs[diff]++; if (diff > FLAGS_maxComponentDiff) { SkDebugf("Expected pixel at (%i %i) exceedds maximum " "component diff of %i: 0x%x, actual 0x%x\n", x, y, FLAGS_maxComponentDiff, *referenceBitmap->getAddr32(x, y), *bitmap->getAddr32(x, y)); SkDELETE(bitmap); SkDELETE(referenceBitmap); return false; } } } SkDELETE(referenceBitmap); for (int i = 1; i <= 255; ++i) { if(diffs[i] > 0) { SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]); } } } if (FLAGS_writeWholeImage) { sk_tools::force_all_opaque(*bitmap); // TODO(epoger): It would be better for the filename (without outputDir) to be passed in // here, and used both for the checksum file and writing into outputDir. SkString inputFilename, outputPath; sk_tools::get_basename(&inputFilename, inputPath); sk_tools::make_filepath(&outputPath, *outputDir, inputFilename); sk_tools::replace_char(&outputPath, '.', '_'); outputPath.append(".png"); if (NULL != jsonSummaryPtr) { SkString outputFileBasename; sk_tools::get_basename(&outputFileBasename, outputPath); jsonSummaryPtr->add(inputFilename.c_str(), outputFileBasename.c_str(), *bitmap); } if (NULL != outputDir) { if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap, SkImageEncoder::kPNG_Type, 100)) { SkDebugf("Failed to draw the picture.\n"); success = false; } } } SkDELETE(bitmap); return success; }
SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : INHERITED(SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)) , fBitmap(bitmap) { SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); }
void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { SkMatrix matrix; SkRect bitmapBounds, tmpSrc, tmpDst; SkBitmap tmpBitmap; bitmapBounds.isetWH(bitmap.width(), bitmap.height()); // Compute matrix from the two rectangles if (src) { tmpSrc = *src; } else { tmpSrc = bitmapBounds; } matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); const SkRect* dstPtr = &dst; const SkBitmap* bitmapPtr = &bitmap; // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if // needed (if the src was clipped). No check needed if src==null. if (src) { if (!bitmapBounds.contains(*src)) { if (!tmpSrc.intersect(bitmapBounds)) { return; // nothing to draw } // recompute dst, based on the smaller tmpSrc matrix.mapRect(&tmpDst, tmpSrc); dstPtr = &tmpDst; } // since we may need to clamp to the borders of the src rect within // the bitmap, we extract a subset. const SkIRect srcIR = tmpSrc.roundOut(); if(bitmap.pixelRef()->getTexture()) { // Accelerated source canvas, don't use extractSubset but readPixels to get the subset. // This way, the pixels are copied in CPU memory instead of GPU memory. bitmap.pixelRef()->readPixels(&tmpBitmap, &srcIR); } else { if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { return; } } bitmapPtr = &tmpBitmap; // Since we did an extract, we need to adjust the matrix accordingly SkScalar dx = 0, dy = 0; if (srcIR.fLeft > 0) { dx = SkIntToScalar(srcIR.fLeft); } if (srcIR.fTop > 0) { dy = SkIntToScalar(srcIR.fTop); } if (dx || dy) { matrix.preTranslate(dx, dy); } SkRect extractedBitmapBounds; extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); if (extractedBitmapBounds == tmpSrc) { // no fractional part in src, we can just call drawBitmap goto USE_DRAWBITMAP; } } else { USE_DRAWBITMAP: // We can go faster by just calling drawBitmap, which will concat the // matrix with the CTM, and try to call drawSprite if it can. If not, // it will make a shader and call drawRect, as we do below. draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); return; } // construct a shader, so we can call drawRect with the dst SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &matrix); if (nullptr == s) { return; } SkPaint paintWithShader(paint); paintWithShader.setStyle(SkPaint::kFill_Style); paintWithShader.setShader(s)->unref(); // Call ourself, in case the subclass wanted to share this setup code // but handle the drawRect code themselves. this->drawRect(draw, *dstPtr, paintWithShader); }
void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { SkASSERT(bm.width() == fBitmap.width()); SkASSERT(bm.height() == fBitmap.height()); fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) fBitmap.lockPixels(); }
LayerAndroid* deserializeLayer(SkStream* stream) { int type = stream->readU8(); if (type == LTNone) return 0; // Cast is to disambiguate between ctors. LayerAndroid *layer; if (type == LTLayerAndroid) layer = new LayerAndroid((RenderLayer*) 0); else if (type == LTScrollableLayerAndroid) layer = new ScrollableLayerAndroid((RenderLayer*) 0); else { XLOG("Unexpected layer type: %d, aborting!", type); return 0; } // Layer fields layer->setShouldInheritFromRootTransform(stream->readBool()); layer->setOpacity(stream->readScalar()); layer->setSize(stream->readScalar(), stream->readScalar()); layer->setPosition(stream->readScalar(), stream->readScalar()); layer->setAnchorPoint(stream->readScalar(), stream->readScalar()); layer->setMatrix(readMatrix(stream)); layer->setChildrenMatrix(readMatrix(stream)); // LayerAndroid fields layer->m_haveClip = stream->readBool(); layer->m_isFixed = stream->readBool(); layer->m_backgroundColorSet = stream->readBool(); layer->m_isIframe = stream->readBool(); layer->m_fixedLeft = readSkLength(stream); layer->m_fixedTop = readSkLength(stream); layer->m_fixedRight = readSkLength(stream); layer->m_fixedBottom = readSkLength(stream); layer->m_fixedMarginLeft = readSkLength(stream); layer->m_fixedMarginTop = readSkLength(stream); layer->m_fixedMarginRight = readSkLength(stream); layer->m_fixedMarginBottom = readSkLength(stream); layer->m_fixedRect = readSkRect(stream); layer->m_renderLayerPos.setX(stream->readS32()); layer->m_renderLayerPos.setY(stream->readS32()); layer->m_backfaceVisibility = stream->readBool(); layer->m_visible = stream->readBool(); layer->m_backgroundColor = stream->readU32(); layer->m_preserves3D = stream->readBool(); layer->m_anchorPointZ = stream->readScalar(); layer->m_drawOpacity = stream->readScalar(); bool hasContentsImage = stream->readBool(); if (hasContentsImage) { int size = stream->readU32(); SkAutoMalloc storage(size); stream->read(storage.get(), size); SkFlattenableReadBuffer buffer(storage.get(), size); SkBitmap contentsImage; contentsImage.unflatten(buffer); SkBitmapRef* imageRef = new SkBitmapRef(contentsImage); layer->setContentsImage(imageRef); delete imageRef; } bool hasRecordingPicture = stream->readBool(); if (hasRecordingPicture) { layer->m_recordingPicture = new SkPicture(stream); } int animationCount = stream->readU32(); // TODO: Support (maybe?) readTransformationMatrix(stream, layer->m_transform); readTransformationMatrix(stream, layer->m_childrenTransform); if (type == LTScrollableLayerAndroid) { ScrollableLayerAndroid* scrollableLayer = static_cast<ScrollableLayerAndroid*>(layer); scrollableLayer->m_scrollLimits.set( stream->readScalar(), stream->readScalar(), stream->readScalar(), stream->readScalar()); } int childCount = stream->readU32(); for (int i = 0; i < childCount; i++) { LayerAndroid *childLayer = deserializeLayer(stream); if (childLayer) layer->addChild(childLayer); } layer->needsRepaint(); XLOG("Created layer with id %d", layer->uniqueId()); return layer; }
bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const SkMatrix& matrix, SkBitmap* result, SkIPoint* loc) { SkBitmap src = this->getInputResult(proxy, source, matrix, loc); if (src.config() != SkBitmap::kARGB_8888_Config) { return false; } if (!fConvolveAlpha && !src.isOpaque()) { src = unpremultiplyBitmap(src); } SkAutoLockPixels alp(src); if (!src.getPixels()) { return false; } result->setConfig(src.config(), src.width(), src.height()); result->allocPixels(); SkIRect interior = SkIRect::MakeXYWH(fTarget.fX, fTarget.fY, src.width() - fKernelSize.fWidth + 1, src.height() - fKernelSize.fHeight + 1); SkIRect top = SkIRect::MakeWH(src.width(), fTarget.fY); SkIRect bottom = SkIRect::MakeLTRB(0, interior.bottom(), src.width(), src.height()); SkIRect left = SkIRect::MakeXYWH(0, interior.top(), fTarget.fX, interior.height()); SkIRect right = SkIRect::MakeLTRB(interior.right(), interior.top(), src.width(), interior.bottom()); filterBorderPixels(src, result, top); filterBorderPixels(src, result, left); filterInteriorPixels(src, result, interior); filterBorderPixels(src, result, right); filterBorderPixels(src, result, bottom); return true; }
status_t s3d_image_sbs_test(void) { printf("[Unit Test] SurfaceFlinger 3D display test !\n\n"); sp<SurfaceComposerClient> client; //sp<SurfaceControl> c; sp<Surface> s; Surface::SurfaceInfo i; SkBitmap sbs; // ready the png image file if (false == SkImageDecoder::DecodeFile("/data/3D_SBS.png", &sbs)) { printf("fail load file"); return INVALID_OPERATION; } // create layer env client = new SurfaceComposerClient(); printf("screen (w, h) = (%d, %d)\n\n", (int)client->getDisplayWidth(0), (int)client->getDisplayHeight(0)); // test set to side by side mode, and pull to topest layer in transaction printf("*** side by side test ...\n"); c = client->createSurface( String8("test-S3D_background"), 0, DRAW_FHD_W, DRAW_FHD_H, PIXEL_FORMAT_RGBA_8888, ISurfaceComposer::eFXSurfaceDim & ISurfaceComposer::eFXSurfaceMask); u = client->createSurface(String8("test-S3D_image"), 0, sbs.width(), sbs.height(), PIXEL_FORMAT_RGBA_8888); //printf("tempc weakcount = %d\n", tempc->getWeakRefs()->getWeakCount()); //c = tempc; //printf("after asign, tempc weakcount = %d, c weakcount = %d\n", tempc->getWeakRefs()->getWeakCount(),c->getWeakRefs()->getWeakCount()); client->openGlobalTransaction(); { c->setLayer(200000); c->setPosition(0, 0); c->setAlpha(1.0f); // black background u->setLayer(210000); u->setPosition(0, 0); } client->closeGlobalTransaction(); printf(" set to SBS mode\n"); client->openGlobalTransaction(); { u->setFlags(ISurfaceComposer::eLayerSideBySide, ISurfaceComposer::eLayerS3DMask); } client->closeGlobalTransaction(); s = u->getSurface(); s->lock(&i); { memcpy(i.bits, sbs.getPixels(), sbs.width() * sbs.height() * sbs.bytesPerPixel()); } s->unlockAndPost(); sleep(1); client->dispose(); return NO_ERROR; }
static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { return *src.getAddr32(x, y); }
static void bitmap_to_pdf_pixels(const SkBitmap& bitmap, SkWStream* out) { if (!bitmap.getPixels()) { size_t size = pixel_count(bitmap) * pdf_color_component_count(bitmap.colorType()); fill_stream(out, '\x00', size); return; } SkBitmap copy; const SkBitmap& bm = not4444(bitmap, ©); SkAutoLockPixels autoLockPixels(bm); switch (bm.colorType()) { case kN32_SkColorType: { SkASSERT(3 == pdf_color_component_count(bitmap.colorType())); SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); for (int y = 0; y < bm.height(); ++y) { const SkPMColor* src = bm.getAddr32(0, y); uint8_t* dst = scanline.get(); for (int x = 0; x < bm.width(); ++x) { SkPMColor color = *src++; U8CPU alpha = SkGetPackedA32(color); if (alpha != SK_AlphaTRANSPARENT) { pmcolor_to_rgb24(color, dst); } else { get_neighbor_avg_color(bm, x, y, dst); } dst += 3; } out->write(scanline.get(), 3 * bm.width()); } return; } case kRGB_565_SkColorType: { SkASSERT(3 == pdf_color_component_count(bitmap.colorType())); SkAutoTMalloc<uint8_t> scanline(3 * bm.width()); for (int y = 0; y < bm.height(); ++y) { const uint16_t* src = bm.getAddr16(0, y); uint8_t* dst = scanline.get(); for (int x = 0; x < bm.width(); ++x) { U16CPU color565 = *src++; *dst++ = SkPacked16ToR32(color565); *dst++ = SkPacked16ToG32(color565); *dst++ = SkPacked16ToB32(color565); } out->write(scanline.get(), 3 * bm.width()); } return; } case kAlpha_8_SkColorType: SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); fill_stream(out, '\x00', pixel_count(bm)); return; case kGray_8_SkColorType: case kIndex_8_SkColorType: SkASSERT(1 == pdf_color_component_count(bitmap.colorType())); // these two formats need no transformation to serialize. for (int y = 0; y < bm.height(); ++y) { out->write(bm.getAddr8(0, y), bm.width()); } return; case kUnknown_SkColorType: case kARGB_4444_SkColorType: default: SkDEBUGFAIL("unexpected color type"); } }
static inline SkPMColor fetch(const SkBitmap& src, int x, int y) { x = SkClampMax(x, src.width() - 1); y = SkClampMax(y, src.height() - 1); return *src.getAddr32(x, y); }
/* Fill out buffer with the compressed format Ganesh expects from a colortable based bitmap. [palette (colortable) + indices]. At the moment Ganesh only supports 8bit version. If Ganesh allowed we others we could detect that the colortable.count is <= 16, and then repack the indices as nibbles to save RAM, but it would take more time (i.e. a lot slower than memcpy), so skipping that for now. Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big as the colortable.count says it is. */ static void build_compressed_data(void* buffer, const SkBitmap& bitmap) { SkASSERT(SkBitmap::kIndex8_Config == bitmap.config()); SkAutoLockPixels alp(bitmap); if (!bitmap.readyToDraw()) { SkDEBUGFAIL("bitmap not ready to draw!"); return; } SkColorTable* ctable = bitmap.getColorTable(); char* dst = (char*)buffer; uint32_t* colorTableDst = reinterpret_cast<uint32_t*>(dst); const uint32_t* colorTableSrc = reinterpret_cast<const uint32_t*>(ctable->lockColors()); SkConvertConfig8888Pixels(colorTableDst, 0, SkCanvas::kRGBA_Premul_Config8888, colorTableSrc, 0, SkCanvas::kNative_Premul_Config8888, ctable->count(), 1); ctable->unlockColors(); // always skip a full 256 number of entries, even if we memcpy'd fewer dst += kGrColorTableSize; if ((unsigned)bitmap.width() == bitmap.rowBytes()) { memcpy(dst, bitmap.getPixels(), bitmap.getSize()); } else { // need to trim off the extra bytes per row size_t width = bitmap.width(); size_t rowBytes = bitmap.rowBytes(); const char* src = (const char*)bitmap.getPixels(); for (int y = 0; y < bitmap.height(); y++) { memcpy(dst, src, width); src += rowBytes; dst += width; } } }
bool SkMagnifierImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, const Context&, SkBitmap* dst, SkIPoint* offset) const { if ((src.colorType() != kN32_SkColorType) || (fSrcRect.width() >= src.width()) || (fSrcRect.height() >= src.height())) { return false; } SkAutoLockPixels alp(src); SkASSERT(src.getPixels()); if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) { return false; } SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height())); if (!device) { return false; } *dst = device->accessBitmap(false); SkAutoLockPixels alp_dst(*dst); SkScalar inv_inset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1; SkScalar inv_x_zoom = fSrcRect.width() / src.width(); SkScalar inv_y_zoom = fSrcRect.height() / src.height(); SkColor* sptr = src.getAddr32(0, 0); SkColor* dptr = dst->getAddr32(0, 0); int width = src.width(), height = src.height(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { SkScalar x_dist = SkMin32(x, width - x - 1) * inv_inset; SkScalar y_dist = SkMin32(y, height - y - 1) * inv_inset; SkScalar weight = 0; static const SkScalar kScalar2 = SkScalar(2); // To create a smooth curve at the corners, we need to work on // a square twice the size of the inset. if (x_dist < kScalar2 && y_dist < kScalar2) { x_dist = kScalar2 - x_dist; y_dist = kScalar2 - y_dist; SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) + SkScalarSquare(y_dist)); dist = SkMaxScalar(kScalar2 - dist, 0); weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1); } else { SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist), SkScalarSquare(y_dist)); weight = SkMinScalar(sqDist, SK_Scalar1); } SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * inv_x_zoom)) + (SK_Scalar1 - weight) * x; SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * inv_y_zoom)) + (SK_Scalar1 - weight) * y; int x_val = SkTPin(SkScalarFloorToInt(x_interp), 0, width - 1); int y_val = SkTPin(SkScalarFloorToInt(y_interp), 0, height - 1); *dptr = sptr[y_val * width + x_val]; dptr++; } } return true; }
static SkSize computeSize(const SkBitmap& bm, const SkMatrix& mat) { SkRect bounds = SkRect::MakeWH(SkIntToScalar(bm.width()), SkIntToScalar(bm.height())); mat.mapRect(&bounds); return SkSize::Make(bounds.width(), bounds.height()); }
static bool getBitmapInfo(const SkBitmap& bm, size_t* bitsPerComponent, CGBitmapInfo* info, bool* upscaleTo32) { if (upscaleTo32) { *upscaleTo32 = false; } switch (bm.config()) { case SkBitmap::kRGB_565_Config: if (upscaleTo32) { *upscaleTo32 = true; } // fall through case SkBitmap::kARGB_8888_Config: *bitsPerComponent = 8; #if SK_PMCOLOR_BYTE_ORDER(R,G,B,A) *info = kCGBitmapByteOrder32Big; if (bm.isOpaque()) { *info |= kCGImageAlphaNoneSkipLast; } else { *info |= kCGImageAlphaPremultipliedLast; } #elif SK_PMCOLOR_BYTE_ORDER(B,G,R,A) // Matches the CGBitmapInfo that Apple recommends for best // performance, used by google chrome. *info = kCGBitmapByteOrder32Little; if (bm.isOpaque()) { *info |= kCGImageAlphaNoneSkipFirst; } else { *info |= kCGImageAlphaPremultipliedFirst; } #else // ...add more formats as required... #warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \ This will probably not work. // Legacy behavior. Perhaps turn this into an error at some // point. *info = kCGBitmapByteOrder32Big; if (bm.isOpaque()) { *info |= kCGImageAlphaNoneSkipLast; } else { *info |= kCGImageAlphaPremultipliedLast; } #endif break; #if 0 case SkBitmap::kRGB_565_Config: // doesn't see quite right. Are they thinking 1555? *bitsPerComponent = 5; *info = kCGBitmapByteOrder16Little | kCGImageAlphaNone; break; #endif case SkBitmap::kARGB_4444_Config: *bitsPerComponent = 4; *info = kCGBitmapByteOrder16Little; if (bm.isOpaque()) { *info |= kCGImageAlphaNoneSkipLast; } else { *info |= kCGImageAlphaPremultipliedLast; } break; default: return false; } return true; }
sk_sp<SkSpecialImage> SkMorphologyImageFilter::filterImageGeneric(bool dilate, SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint inputOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); if (!input) { return nullptr; } SkIRect bounds; input = this->applyCropRect(this->mapContext(ctx), input.get(), &inputOffset, &bounds); if (!input) { return nullptr; } SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()), SkIntToScalar(this->radius().height())); ctx.ctm().mapVectors(&radius, 1); int width = SkScalarFloorToInt(radius.fX); int height = SkScalarFloorToInt(radius.fY); if (width < 0 || height < 0) { return nullptr; } SkIRect srcBounds = bounds; srcBounds.offset(-inputOffset); if (0 == width && 0 == height) { offset->fX = bounds.left(); offset->fY = bounds.top(); return input->makeSubset(srcBounds); } #if SK_SUPPORT_GPU if (input->peekTexture() && input->peekTexture()->getContext()) { auto type = dilate ? GrMorphologyEffect::kDilate_MorphologyType : GrMorphologyEffect::kErode_MorphologyType; sk_sp<SkSpecialImage> result(apply_morphology(input.get(), srcBounds, type, SkISize::Make(width, height))); if (result) { offset->fX = bounds.left(); offset->fY = bounds.top(); } return result; } #endif SkPixmap inputPixmap; if (!input->peekPixels(&inputPixmap)) { return nullptr; } if (inputPixmap.colorType() != kN32_SkColorType) { return nullptr; } SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), inputPixmap.colorType(), inputPixmap.alphaType()); SkBitmap dst; if (!dst.tryAllocPixels(info)) { return nullptr; } SkAutoLockPixels dstLock(dst); SkMorphologyImageFilter::Proc procX, procY; if (dilate) { procX = SkOpts::dilate_x; procY = SkOpts::dilate_y; } else { procX = SkOpts::erode_x; procY = SkOpts::erode_y; } if (width > 0 && height > 0) { SkBitmap tmp; if (!tmp.tryAllocPixels(info)) { return nullptr; } SkAutoLockPixels tmpLock(tmp); call_proc_X(procX, inputPixmap, &tmp, width, srcBounds); SkIRect tmpBounds = SkIRect::MakeWH(srcBounds.width(), srcBounds.height()); call_proc_Y(procY, tmp.getAddr32(tmpBounds.left(), tmpBounds.top()), tmp.rowBytesAsPixels(), &dst, height, tmpBounds); } else if (width > 0) { call_proc_X(procX, inputPixmap, &dst, width, srcBounds); } else if (height > 0) { call_proc_Y(procY, inputPixmap.addr32(srcBounds.left(), srcBounds.top()), inputPixmap.rowBytesAsPixels(), &dst, height, srcBounds); } offset->fX = bounds.left(); offset->fY = bounds.top(); return SkSpecialImage::MakeFromRaster(source->internal_getProxy(), SkIRect::MakeWH(bounds.width(), bounds.height()), dst); }
void Clipboard::WriteBitmap(const SkBitmap& bitmap) { QImage image(reinterpret_cast<const uchar *>(bitmap.getPixels()), bitmap.width(), bitmap.height(), QImage::Format_ARGB32); getUncommittedData()->setImageData(image.copy()); }
static void test_peekpixels(skiatest::Reporter* reporter) { const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); SkPixmap pmap; SkBitmap bm; // empty should return false REPORTER_ASSERT(reporter, !bm.peekPixels(nullptr)); REPORTER_ASSERT(reporter, !bm.peekPixels(&pmap)); // no pixels should return false bm.setInfo(SkImageInfo::MakeN32Premul(10, 10)); REPORTER_ASSERT(reporter, !bm.peekPixels(nullptr)); REPORTER_ASSERT(reporter, !bm.peekPixels(&pmap)); // real pixels should return true bm.allocPixels(info); REPORTER_ASSERT(reporter, bm.peekPixels(nullptr)); REPORTER_ASSERT(reporter, bm.peekPixels(&pmap)); REPORTER_ASSERT(reporter, pmap.info() == bm.info()); REPORTER_ASSERT(reporter, pmap.addr() == bm.getPixels()); REPORTER_ASSERT(reporter, pmap.rowBytes() == bm.rowBytes()); REPORTER_ASSERT(reporter, pmap.ctable() == bm.getColorTable()); }
void SkScalerContext::getImage(const SkGlyph& origGlyph) { const SkGlyph* glyph = &origGlyph; SkGlyph tmpGlyph; if (fMaskFilter) { // restore the prefilter bounds tmpGlyph.init(origGlyph.fID); // need the original bounds, sans our maskfilter SkMaskFilter* mf = fMaskFilter; fMaskFilter = NULL; // temp disable this->getMetrics(&tmpGlyph); fMaskFilter = mf; // restore tmpGlyph.fImage = origGlyph.fImage; // we need the prefilter bounds to be <= filter bounds SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); glyph = &tmpGlyph; } if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) { SkPath devPath, fillPath; SkMatrix fillToDevMatrix; this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix); const bool lcdMode = fRec.fMaskFormat == SkMask::kHorizontalLCD_Format || fRec.fMaskFormat == SkMask::kVerticalLCD_Format; if (fRasterizer) { SkMask mask; glyph->toMask(&mask); mask.fFormat = SkMask::kA8_Format; sk_bzero(glyph->fImage, mask.computeImageSize()); if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL, fMaskFilter, &mask, SkMask::kJustRenderImage_CreateMode)) { return; } } else { SkBitmap bm; SkBitmap::Config config; SkMatrix matrix; SkRegion clip; SkPaint paint; SkDraw draw; if (SkMask::kA8_Format == fRec.fMaskFormat || lcdMode) { config = SkBitmap::kA8_Config; paint.setAntiAlias(true); } else { SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat); config = SkBitmap::kA1_Config; paint.setAntiAlias(false); } clip.setRect(0, 0, glyph->fWidth, glyph->fHeight); matrix.setTranslate(-SkIntToScalar(glyph->fLeft), -SkIntToScalar(glyph->fTop)); bm.setConfig(config, glyph->fWidth, glyph->fHeight, glyph->rowBytes()); bm.setPixels(glyph->fImage); sk_bzero(glyph->fImage, bm.height() * bm.rowBytes()); draw.fClip = &clip; draw.fMatrix = &matrix; draw.fBitmap = &bm; draw.fBounder = NULL; draw.drawPath(devPath, paint); } if (lcdMode) glyph->expandA8ToLCD(); } else { this->getGlyphContext(*glyph)->generateImage(*glyph); } if (fMaskFilter) { SkMask srcM, dstM; SkMatrix matrix; // the src glyph image shouldn't be 3D SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); glyph->toMask(&srcM); fRec.getMatrixFrom2x2(&matrix); if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width()); int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height()); int dstRB = origGlyph.rowBytes(); int srcRB = dstM.fRowBytes; const uint8_t* src = (const uint8_t*)dstM.fImage; uint8_t* dst = (uint8_t*)origGlyph.fImage; if (SkMask::k3D_Format == dstM.fFormat) { // we have to copy 3 times as much height *= 3; } // clean out our glyph, since it may be larger than dstM //sk_bzero(dst, height * dstRB); while (--height >= 0) { memcpy(dst, src, width); src += srcRB; dst += dstRB; } SkMask::FreeImage(dstM.fImage); } } // check to see if we should filter the alpha channel if (NULL == fMaskFilter && fRec.fMaskFormat != SkMask::kBW_Format && fRec.fMaskFormat != SkMask::kLCD16_Format && (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) { const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable; if (NULL != table) { uint8_t* dst = (uint8_t*)origGlyph.fImage; unsigned rowBytes = origGlyph.rowBytes(); for (int y = origGlyph.fHeight - 1; y >= 0; --y) { for (int x = origGlyph.fWidth - 1; x >= 0; --x) dst[x] = table[dst[x]]; dst += rowBytes; } } } }
void HwcDebug::dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]) { char dumpLogStrPng[128] = ""; char dumpLogStrRaw[128] = ""; bool needDumpPng = (mDumpCntrPng <= mDumpCntLimPng)? true:false; bool needDumpRaw = (mDumpCntrRaw <= mDumpCntLimRaw)? true:false; if (needDumpPng) { snprintf(dumpLogStrPng, sizeof(dumpLogStrPng), "[png-dump-frame: %03d of %03d]", mDumpCntrPng, mDumpCntLimPng); } if (needDumpRaw) { snprintf(dumpLogStrRaw, sizeof(dumpLogStrRaw), "[raw-dump-frame: %03d of %03d]", mDumpCntrRaw, mDumpCntLimRaw); } if (!(needDumpPng || needDumpRaw)) return; if (NULL == hwLayers) { ALOGE("Display[%s] Layer[%zu] %s%s Error: No hwc layers to dump.", mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng); return; } hwc_layer_1_t *layer = &hwLayers[layerIndex]; private_handle_t *hnd = (private_handle_t *)layer->handle; char pixFormatStr[32] = "None"; if (NULL == hnd) { ALOGI("Display[%s] Layer[%zu] %s%s Skipping dump: Bufferless layer.", mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng); return; } getHalPixelFormatStr(hnd->format, pixFormatStr); #ifdef QCOM_BSP if (needDumpPng && hnd->base) { bool bResult = false; char dumpFilename[PATH_MAX]; SkBitmap *tempSkBmp = new SkBitmap(); SkColorType tempSkBmpColor = kUnknown_SkColorType; snprintf(dumpFilename, sizeof(dumpFilename), "%s/sfdump%03d.layer%zu.%s.png", mDumpDirPng, mDumpCntrPng, layerIndex, mDisplayName); switch (hnd->format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: tempSkBmpColor = kRGBA_8888_SkColorType; break; case HAL_PIXEL_FORMAT_BGRA_8888: tempSkBmpColor = kBGRA_8888_SkColorType; break; case HAL_PIXEL_FORMAT_RGB_565: tempSkBmpColor = kRGB_565_SkColorType; break; case HAL_PIXEL_FORMAT_RGB_888: default: tempSkBmpColor = kUnknown_SkColorType; break; } if (kUnknown_SkColorType != tempSkBmpColor) { tempSkBmp->setInfo(SkImageInfo::Make(getWidth(hnd), getHeight(hnd), tempSkBmpColor, kIgnore_SkAlphaType), 0); tempSkBmp->setPixels((void*)hnd->base); bResult = SkImageEncoder::EncodeFile(dumpFilename, *tempSkBmp, SkImageEncoder::kPNG_Type, 100); ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s", mDisplayName, layerIndex, dumpLogStrPng, dumpFilename, bResult ? "Success" : "Fail"); } else { ALOGI("Display[%s] Layer[%zu] %s Skipping dump: Unsupported layer" " format %s for png encoder", mDisplayName, layerIndex, dumpLogStrPng, pixFormatStr); } delete tempSkBmp; // Calls SkBitmap::freePixels() internally. } #endif if (needDumpRaw && hnd->base) { char dumpFilename[PATH_MAX]; bool bResult = false; snprintf(dumpFilename, sizeof(dumpFilename), "%s/sfdump%03d.layer%zu.%dx%d.%s.%s.raw", mDumpDirRaw, mDumpCntrRaw, layerIndex, getWidth(hnd), getHeight(hnd), pixFormatStr, mDisplayName); FILE* fp = fopen(dumpFilename, "w+"); if (NULL != fp) { bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp); fclose(fp); } ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s", mDisplayName, layerIndex, dumpLogStrRaw, dumpFilename, bResult ? "Success" : "Fail"); } }
void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { SkMatrix matrix; SkRect bitmapBounds, tmpSrc, tmpDst; SkBitmap tmpBitmap; bitmapBounds.isetWH(bitmap.width(), bitmap.height()); // Compute matrix from the two rectangles if (src) { tmpSrc = *src; } else { tmpSrc = bitmapBounds; } matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); const SkRect* dstPtr = &dst; const SkBitmap* bitmapPtr = &bitmap; // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if // needed (if the src was clipped). No check needed if src==null. if (src) { if (!bitmapBounds.contains(*src)) { if (!tmpSrc.intersect(bitmapBounds)) { return; // nothing to draw } // recompute dst, based on the smaller tmpSrc matrix.mapRect(&tmpDst, tmpSrc); dstPtr = &tmpDst; } } if (src && !src->contains(bitmapBounds) && SkCanvas::kFast_SrcRectConstraint == constraint && paint.getFilterQuality() != kNone_SkFilterQuality) { // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap, // but we must use a shader w/ dst bounds (which can access all of the bitmap needed). goto USE_SHADER; } if (src) { // since we may need to clamp to the borders of the src rect within // the bitmap, we extract a subset. const SkIRect srcIR = tmpSrc.roundOut(); if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { return; } bitmapPtr = &tmpBitmap; // Since we did an extract, we need to adjust the matrix accordingly SkScalar dx = 0, dy = 0; if (srcIR.fLeft > 0) { dx = SkIntToScalar(srcIR.fLeft); } if (srcIR.fTop > 0) { dy = SkIntToScalar(srcIR.fTop); } if (dx || dy) { matrix.preTranslate(dx, dy); } SkRect extractedBitmapBounds; extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); if (extractedBitmapBounds == tmpSrc) { // no fractional part in src, we can just call drawBitmap goto USE_DRAWBITMAP; } } else { USE_DRAWBITMAP: // We can go faster by just calling drawBitmap, which will concat the // matrix with the CTM, and try to call drawSprite if it can. If not, // it will make a shader and call drawRect, as we do below. if (CanApplyDstMatrixAsCTM(matrix, paint)) { draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); return; } } USE_SHADER: // Since the shader need only live for our stack-frame, pass in a custom allocator. This // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap // if its mutable, since that precaution is not needed (give the short lifetime of the shader). SkTBlitterAllocator allocator; // construct a shader, so we can call drawRect with the dst auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &matrix, kNever_SkCopyPixelsMode, &allocator); if (!s) { return; } // we deliberately add a ref, since the allocator wants to be the last owner s.get()->ref(); SkPaint paintWithShader(paint); paintWithShader.setStyle(SkPaint::kFill_Style); paintWithShader.setShader(s); // Call ourself, in case the subclass wanted to share this setup code // but handle the drawRect code themselves. this->drawRect(draw, *dstPtr, paintWithShader); }