bool PluginWidgetParent::RecvCreate(nsresult* aResult) { PWLOG("PluginWidgetParent::RecvCreate()\n"); mWidget = do_CreateInstance(kWidgetCID, aResult); NS_ASSERTION(NS_SUCCEEDED(*aResult), "widget create failure"); #if defined(MOZ_WIDGET_GTK) // We need this currently just for GTK in setting up a socket widget // we can send over to content -> plugin. PLUG_NewPluginNativeWindow((nsPluginNativeWindow**)&mWrapper); if (!mWrapper) { KillWidget(); return false; } // Give a copy of this to the widget, which handles some update // work for us. mWidget->SetNativeData(NS_NATIVE_PLUGIN_OBJECT_PTR, (uintptr_t)mWrapper.get()); #endif // This returns the top level window widget nsCOMPtr<nsIWidget> parentWidget = GetTabParent()->GetWidget(); // If this fails, bail. if (!parentWidget) { *aResult = NS_ERROR_NOT_AVAILABLE; KillWidget(); return true; } nsWidgetInitData initData; initData.mWindowType = eWindowType_plugin_ipc_chrome; initData.mUnicode = false; initData.clipChildren = true; initData.clipSiblings = true; *aResult = mWidget->Create(parentWidget.get(), nullptr, nsIntRect(0,0,0,0), &initData); if (NS_FAILED(*aResult)) { KillWidget(); // This should never fail, abort. return false; } DebugOnly<nsresult> drv; drv = mWidget->EnableDragDrop(true); NS_ASSERTION(NS_SUCCEEDED(drv), "widget call failure"); #if defined(MOZ_WIDGET_GTK) // For setup, initially GTK code expects 'window' to hold the parent. mWrapper->window = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT); drv = mWrapper->CreateXEmbedWindow(false); NS_ASSERTION(NS_SUCCEEDED(drv), "widget call failure"); mWrapper->SetAllocation(); PWLOG("Plugin XID=%p\n", (void*)mWrapper->window); #elif defined(XP_WIN) DebugOnly<DWORD> winres = ::SetPropW((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW), mozilla::dom::kPluginWidgetContentParentProperty, GetTabParent()->Manager()->AsContentParent()); NS_ASSERTION(winres, "SetPropW call failure"); #endif // This is a special call we make to nsBaseWidget to register this // window as a remote plugin window which is expected to receive // visibility updates from the compositor, which ships this data // over with corresponding layer updates. mWidget->RegisterPluginWindowForRemoteUpdates(); return true; }
NS_IMETHODIMP nsScriptableRegion::SetToRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) { mRegion = nsIntRect(aX, aY, aWidth, aHeight); return NS_OK; }
/*static*/ nsIntRect gfxAlphaRecovery::AlignRectForSubimageRecovery(const nsIntRect& aRect, gfxImageSurface* aSurface) { NS_ASSERTION(gfxASurface::ImageFormatARGB32 == aSurface->Format(), "Thebes grew support for non-ARGB32 COLOR_ALPHA?"); static const PRInt32 kByteAlignLog2 = GoodAlignmentLog2(); static const PRInt32 bpp = 4; static const PRInt32 pixPerAlign = (1 << kByteAlignLog2) / bpp; // // We're going to create a subimage of the surface with size // <sw,sh> for alpha recovery, and want a SIMD fast-path. The // rect <x,y, w,h> /needs/ to be redrawn, but it might not be // properly aligned for SIMD. So we want to find a rect <x',y', // w',h'> that's a superset of what needs to be redrawn but is // properly aligned. Proper alignment is // // BPP * (x' + y' * sw) \cong 0 (mod ALIGN) // BPP * w' \cong BPP * sw (mod ALIGN) // // (We assume the pixel at surface <0,0> is already ALIGN'd.) // That rect (obviously) has to fit within the surface bounds, and // we should also minimize the extra pixels redrawn only for // alignment's sake. So we also want // // minimize <x',y', w',h'> // 0 <= x' <= x // 0 <= y' <= y // w <= w' <= sw // h <= h' <= sh // // This is a messy integer non-linear programming problem, except // ... we can assume that ALIGN/BPP is a very small constant. So, // brute force is viable. The algorithm below will find a // solution if one exists, but isn't guaranteed to find the // minimum solution. (For SSE2, ALIGN/BPP = 4, so it'll do at // most 64 iterations below). In what's likely the common case, // an already-aligned rectangle, it only needs 1 iteration. // // Is this alignment worth doing? Recovering alpha will take work // proportional to w*h (assuming alpha recovery computation isn't // memory bound). This analysis can lead to O(w+h) extra work // (with small constants). In exchange, we expect to shave off a // ALIGN/BPP constant by using SIMD-ized alpha recovery. So as // w*h diverges from w+h, the win factor approaches ALIGN/BPP. We // only really care about the w*h >> w+h case anyway; others // should be fast enough even with the overhead. (Unless the cost // of repainting the expanded rect is high, but in that case // SIMD-ized alpha recovery won't make a difference so this code // shouldn't be called.) // gfxIntSize surfaceSize = aSurface->GetSize(); const PRInt32 stride = bpp * surfaceSize.width; if (stride != aSurface->Stride()) { NS_WARNING("Unexpected stride, falling back on slow alpha recovery"); return aRect; } const PRInt32 x = aRect.x, y = aRect.y, w = aRect.width, h = aRect.height; const PRInt32 r = x + w; const PRInt32 sw = surfaceSize.width; const PRInt32 strideAlign = ByteAlignment(kByteAlignLog2, stride); // The outer two loops below keep the rightmost (|r| above) and // bottommost pixels in |aRect| fixed wrt <x,y>, to ensure that we // return only a superset of the original rect. These loops // search for an aligned top-left pixel by trying to expand <x,y> // left and up by <dx,dy> pixels, respectively. // // Then if a properly-aligned top-left pixel is found, the // innermost loop tries to find an aligned stride by moving the // rightmost pixel rightward by dr. PRInt32 dx, dy, dr; for (dy = 0; (dy < pixPerAlign) && (y - dy >= 0); ++dy) { for (dx = 0; (dx < pixPerAlign) && (x - dx >= 0); ++dx) { if (0 != ByteAlignment(kByteAlignLog2, bpp * (x - dx), y - dy, stride)) { continue; } for (dr = 0; (dr < pixPerAlign) && (r + dr <= sw); ++dr) { if (strideAlign == ByteAlignment(kByteAlignLog2, bpp * (w + dr + dx))) { goto FOUND_SOLUTION; } } } } // Didn't find a solution. return aRect; FOUND_SOLUTION: nsIntRect solution = nsIntRect(x - dx, y - dy, w + dr + dx, h + dy); NS_ABORT_IF_FALSE(nsIntRect(0, 0, sw, surfaceSize.height).Contains(solution), "'Solution' extends outside surface bounds!"); return solution; }
SimpleTiledLayerTile SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile, const nsIntPoint& aTileOrigin, const nsIntRegion& aDirtyRegion) { PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile"); static gfx::IntSize kTileSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()); gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType()); // if this is true, we're using a separate buffer to do our drawing first bool doBufferedDrawing = true; bool fullPaint = false; RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle(); if (!textureClient) { NS_WARNING("TextureClient allocation failed"); return SimpleTiledLayerTile(); } if (!textureClient->Lock(OPEN_READ_WRITE)) { NS_WARNING("TextureClient lock failed"); return SimpleTiledLayerTile(); } if (!textureClient->CanExposeDrawTarget()) { doBufferedDrawing = false; } RefPtr<DrawTarget> drawTarget; unsigned char *bufferData = nullptr; // these are set/updated differently based on doBufferedDrawing nsIntRect drawBounds; nsIntRegion drawRegion; nsIntRegion invalidateRegion; RefPtr<DrawTarget> srcDT; uint8_t* srcData = nullptr; int32_t srcStride = 0; gfx::IntSize srcSize; gfx::SurfaceFormat srcFormat = gfx::SurfaceFormat::UNKNOWN; if (doBufferedDrawing) { // try to directly access the pixels of the TextureClient srcDT = textureClient->GetAsDrawTarget(); if (srcDT->LockBits(&srcData, &srcSize, &srcStride, &srcFormat)) { if (!aTile.mCachedBuffer) { aTile.mCachedBuffer = SharedBuffer::Create(srcStride * srcSize.height); fullPaint = true; } bufferData = (unsigned char*) aTile.mCachedBuffer->Data(); drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData, kTileSize, srcStride, tileFormat); if (fullPaint) { drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height); drawRegion = nsIntRegion(drawBounds); } else { drawBounds = aDirtyRegion.GetBounds(); drawRegion = nsIntRegion(drawBounds); if (GetContentType() == gfxContentType::COLOR_ALPHA) drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y, drawBounds.width, drawBounds.height)); } } else { // failed to obtain the client as an ImageSurface doBufferedDrawing = false; } } // this might get set above if we couldn't extract out a buffer if (!doBufferedDrawing) { drawTarget = textureClient->GetAsDrawTarget(); fullPaint = true; drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height); drawRegion = nsIntRegion(drawBounds); if (GetContentType() == gfxContentType::COLOR_ALPHA) drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height)); } // do the drawing RefPtr<gfxContext> ctxt = new gfxContext(drawTarget); ctxt->Scale(mResolution, mResolution); ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y)); mCallback(mThebesLayer, ctxt, drawRegion, fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED? invalidateRegion, mCallbackData); ctxt = nullptr; if (doBufferedDrawing) { memcpy(srcData, bufferData, srcSize.height * srcStride); bufferData = nullptr; srcDT->ReleaseBits(srcData); srcDT = nullptr; } drawTarget = nullptr; textureClient->Unlock(); if (!mCompositableClient->AddTextureClient(textureClient)) { NS_WARNING("Failed to add tile TextureClient [simple]"); return SimpleTiledLayerTile(); } // aTile.mCachedBuffer was set earlier aTile.mTileBuffer = textureClient; aTile.mManager = mManager; aTile.mLastUpdate = TimeStamp::Now(); return aTile; }
void nsJPEGDecoder::OutputScanlines(bool* suspend) { *suspend = false; const uint32_t top = mInfo.output_scanline; while ((mInfo.output_scanline < mInfo.output_height)) { uint32_t* imageRow = nullptr; if (mDownscaler) { imageRow = reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer()); } else { imageRow = reinterpret_cast<uint32_t*>(mImageData) + (mInfo.output_scanline * mInfo.output_width); } MOZ_ASSERT(imageRow, "Should have a row buffer here"); if (mInfo.out_color_space == MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB) { // Special case: scanline will be directly converted into packed ARGB if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) { *suspend = true; // suspend break; } if (mDownscaler) { mDownscaler->CommitRow(); } continue; // all done for this row! } JSAMPROW sampleRow = (JSAMPROW)imageRow; if (mInfo.output_components == 3) { // Put the pixels at end of row to enable in-place expansion sampleRow += mInfo.output_width; } // Request one scanline. Returns 0 or 1 scanlines. if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) { *suspend = true; // suspend break; } if (mTransform) { JSAMPROW source = sampleRow; if (mInfo.out_color_space == JCS_GRAYSCALE) { // Convert from the 1byte grey pixels at begin of row // to the 3byte RGB byte pixels at 'end' of row sampleRow += mInfo.output_width; } qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width); // Move 3byte RGB data to end of row if (mInfo.out_color_space == JCS_CMYK) { memmove(sampleRow + mInfo.output_width, sampleRow, 3 * mInfo.output_width); sampleRow += mInfo.output_width; } } else { if (mInfo.out_color_space == JCS_CMYK) { // Convert from CMYK to RGB // We cannot convert directly to Cairo, as the CMSRGBTransform // may wants to do a RGB transform... // Would be better to have platform CMSenabled transformation // from CMYK to (A)RGB... cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width); sampleRow += mInfo.output_width; } if (mCMSMode == eCMSMode_All) { // No embedded ICC profile - treat as sRGB qcms_transform* transform = gfxPlatform::GetCMSRGBTransform(); if (transform) { qcms_transform_data(transform, sampleRow, sampleRow, mInfo.output_width); } } } // counter for while() loops below uint32_t idx = mInfo.output_width; // copy as bytes until source pointer is 32-bit-aligned for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) { *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]); sampleRow += 3; } // copy pixels in blocks of 4 while (idx >= 4) { GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow); idx -= 4; sampleRow += 12; imageRow += 4; } // copy remaining pixel(s) while (idx--) { // 32-bit read of final pixel will exceed buffer, so read bytes *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]); sampleRow += 3; } if (mDownscaler) { mDownscaler->CommitRow(); } } if (mDownscaler && mDownscaler->HasInvalidation()) { DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect(); PostInvalidation(invalidRect.mOriginalSizeRect, Some(invalidRect.mTargetSizeRect)); MOZ_ASSERT(!mDownscaler->HasInvalidation()); } else if (!mDownscaler && top != mInfo.output_scanline) { PostInvalidation(nsIntRect(0, top, mInfo.output_width, mInfo.output_scanline - top)); } }
void ClientTiledThebesLayer::BeginPaint() { if (ClientManager()->IsRepeatTransaction()) { return; } mPaintData.mLowPrecisionPaintCount = 0; mPaintData.mPaintFinished = false; // Calculate the transform required to convert screen space into layer space mPaintData.mTransformScreenToLayer = GetEffectiveTransform(); // XXX Not sure if this code for intermediate surfaces is correct. // It rarely gets hit though, and shouldn't have terrible consequences // even if it is wrong. for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) { if (parent->UseIntermediateSurface()) { mPaintData.mTransformScreenToLayer.PreMultiply(parent->GetEffectiveTransform()); } } mPaintData.mTransformScreenToLayer.Invert(); // Compute the critical display port in layer space. mPaintData.mLayerCriticalDisplayPort.SetEmpty(); const gfx::Rect& criticalDisplayPort = GetParent()->GetFrameMetrics().mCriticalDisplayPort; if (!criticalDisplayPort.IsEmpty()) { gfxRect transformedCriticalDisplayPort = mPaintData.mTransformScreenToLayer.TransformBounds( gfxRect(criticalDisplayPort.x, criticalDisplayPort.y, criticalDisplayPort.width, criticalDisplayPort.height)); transformedCriticalDisplayPort.RoundOut(); mPaintData.mLayerCriticalDisplayPort = nsIntRect(transformedCriticalDisplayPort.x, transformedCriticalDisplayPort.y, transformedCriticalDisplayPort.width, transformedCriticalDisplayPort.height); } // Calculate the frame resolution. mPaintData.mResolution.SizeTo(1, 1); for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) { const FrameMetrics& metrics = parent->GetFrameMetrics(); mPaintData.mResolution.width *= metrics.mResolution.width; mPaintData.mResolution.height *= metrics.mResolution.height; } // Calculate the scroll offset since the last transaction, and the // composition bounds. mPaintData.mCompositionBounds.SetEmpty(); mPaintData.mScrollOffset.MoveTo(0, 0); Layer* primaryScrollable = ClientManager()->GetPrimaryScrollableLayer(); if (primaryScrollable) { const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics(); mPaintData.mScrollOffset = metrics.mScrollOffset; gfxRect transformedViewport = mPaintData.mTransformScreenToLayer.TransformBounds( gfxRect(metrics.mCompositionBounds.x, metrics.mCompositionBounds.y, metrics.mCompositionBounds.width, metrics.mCompositionBounds.height)); transformedViewport.RoundOut(); mPaintData.mCompositionBounds = nsIntRect(transformedViewport.x, transformedViewport.y, transformedViewport.width, transformedViewport.height); } }
void CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) { AutoRemoveTexture autoRemove(this); if (mBuffer && (mBuffer->IsImmutable() || mBuffer->GetSize() != aSize)) { autoRemove.mTexture = mBuffer; mBuffer = nullptr; } bool bufferCreated = false; if (!mBuffer) { bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE); gfxContentType contentType = isOpaque ? gfxContentType::COLOR : gfxContentType::COLOR_ALPHA; gfx::SurfaceFormat surfaceFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType); TextureFlags flags = TextureFlags::DEFAULT; if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) { flags |= TextureFlags::ORIGIN_BOTTOM_LEFT; } mBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aLayer); if (!mBuffer) { NS_WARNING("Failed to allocate the TextureClient"); return; } MOZ_ASSERT(mBuffer->CanExposeDrawTarget()); bufferCreated = true; } bool updated = false; { TextureClientAutoLock autoLock(mBuffer, OpenMode::OPEN_WRITE_ONLY); if (!autoLock.Succeeded()) { mBuffer = nullptr; return; } RefPtr<DrawTarget> target = mBuffer->BorrowDrawTarget(); if (target) { aLayer->UpdateTarget(target); updated = true; } } if (bufferCreated && !AddTextureClient(mBuffer)) { mBuffer = nullptr; return; } if (updated) { AutoTArray<CompositableForwarder::TimedTextureClient,1> textures; CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = mBuffer; t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBuffer->GetSize()); t->mFrameID = mFrameID; t->mInputFrameID = VRManagerChild::Get()->GetInputFrameID(); GetForwarder()->UseTextures(this, textures); mBuffer->SyncWithObject(GetForwarder()->GetSyncObject()); } }
bool HwcComposer2D::PrepareLayerList(Layer* aLayer, const nsIntRect& aClip, const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform) { // NB: we fall off this path whenever there are container layers // that require intermediate surfaces. That means all the // GetEffective*() coordinates are relative to the framebuffer. bool fillColor = false; const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); if (visibleRegion.IsEmpty()) { return true; } float opacity = aLayer->GetEffectiveOpacity(); if (opacity <= 0) { LOGD("Layer is fully transparent so skip rendering"); return true; } else if (opacity < 1) { LOGD("Layer has planar semitransparency which is unsupported"); return false; } if (visibleRegion.GetNumRects() > 1) { // FIXME/bug 808339 LOGD("Layer has nontrivial visible region"); return false; } nsIntRect clip; if (!CalculateClipRect(aParentTransform * aGLWorldTransform, aLayer->GetEffectiveClipRect(), aClip, &clip)) { LOGD("Clip rect is empty. Skip layer"); return true; } gfxMatrix transform; const gfx3DMatrix& transform3D = aLayer->GetEffectiveTransform(); if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) { LOGD("Layer has a 3D transform or a non-square angle rotation"); return false; } if (ContainerLayer* container = aLayer->AsContainerLayer()) { if (container->UseIntermediateSurface()) { LOGD("Container layer needs intermediate surface"); return false; } nsAutoTArray<Layer*, 12> children; container->SortChildrenBy3DZOrder(children); for (uint32_t i = 0; i < children.Length(); i++) { if (!PrepareLayerList(children[i], clip, transform, aGLWorldTransform)) { return false; } } return true; } LayerOGL* layerGL = static_cast<LayerOGL*>(aLayer->ImplData()); LayerRenderState state = layerGL->GetRenderState(); if (!state.mSurface || state.mSurface->type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) { if (aLayer->AsColorLayer() && mColorFill) { fillColor = true; } else { LOGD("Layer doesn't have a gralloc buffer"); return false; } } if (state.BufferRotated()) { LOGD("Layer has a rotated buffer"); return false; } // OK! We can compose this layer with hwc. int current = mList ? mList->numHwLayers : 0; if (!mList || current >= mMaxLayerCount) { if (!ReallocLayerList() || current >= mMaxLayerCount) { LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); return false; } } sp<GraphicBuffer> buffer = fillColor ? nullptr : GrallocBufferActor::GetFrom(*state.mSurface); nsIntRect visibleRect = visibleRegion.GetBounds(); nsIntRect bufferRect; if (fillColor) { bufferRect = nsIntRect(visibleRect); } else { if(state.mHasOwnOffset) { bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, int(buffer->getWidth()), int(buffer->getHeight())); } else { bufferRect = nsIntRect(visibleRect.x, visibleRect.y, int(buffer->getWidth()), int(buffer->getHeight())); } } hwc_layer_t& hwcLayer = mList->hwLayers[current]; if(!PrepareLayerRects(visibleRect, transform * aGLWorldTransform, clip, bufferRect, &(hwcLayer.sourceCrop), &(hwcLayer.displayFrame))) { return true; } buffer_handle_t handle = fillColor ? nullptr : buffer->getNativeBuffer()->handle; hwcLayer.handle = handle; hwcLayer.flags = 0; hwcLayer.hints = 0; hwcLayer.blending = HWC_BLENDING_NONE; hwcLayer.compositionType = HWC_USE_COPYBIT; if (!fillColor) { gfxMatrix rotation = transform * aGLWorldTransform; // Compute fuzzy equal like PreservesAxisAlignedRectangles() if (fabs(rotation.xx) < 1e-6) { if (rotation.xy < 0) { hwcLayer.transform = HWC_TRANSFORM_ROT_90; LOGD("Layer buffer rotated 90 degrees"); } else { hwcLayer.transform = HWC_TRANSFORM_ROT_270; LOGD("Layer buffer rotated 270 degrees"); } } else if (rotation.xx < 0) { hwcLayer.transform = HWC_TRANSFORM_ROT_180; LOGD("Layer buffer rotated 180 degrees"); } else { hwcLayer.transform = 0; } hwcLayer.transform |= state.YFlipped() ? HWC_TRANSFORM_FLIP_V : 0; hwc_region_t region; region.numRects = 1; region.rects = &(hwcLayer.displayFrame); hwcLayer.visibleRegionScreen = region; } else { hwcLayer.flags |= HWC_COLOR_FILL; ColorLayer* colorLayer = static_cast<ColorLayer*>(layerGL->GetLayer()); hwcLayer.transform = colorLayer->GetColor().Packed(); } mList->numHwLayers++; return true; }
virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) { return nsIntRect(); }
void AsyncPanZoomController::UpdateViewportSize(int width, int height) { ReentrantMonitorAutoEnter mon(mReentrantMonitor); FrameMetrics metrics = GetFrameMetrics(); metrics.mViewport = nsIntRect(0, 0, width, height); SetFrameMetrics(metrics); }
void LayerManagerComposite::RenderToPresentationSurface() { #ifdef MOZ_WIDGET_ANDROID if (!AndroidBridge::Bridge()) { return; } void* window = AndroidBridge::Bridge()->GetPresentationWindow(); if (!window) { return; } EGLSurface surface = AndroidBridge::Bridge()->GetPresentationSurface(); if (!surface) { //create surface; surface = GLContextProviderEGL::CreateEGLSurface(window); if (!surface) { return; } AndroidBridge::Bridge()->SetPresentationSurface(surface); } CompositorOGL* compositor = static_cast<CompositorOGL*>(mCompositor.get()); GLContext* gl = compositor->gl(); GLContextEGL* egl = GLContextEGL::Cast(gl); if (!egl) { return; } const IntSize windowSize = AndroidBridge::Bridge()->GetNativeWindowSize(window); #elif defined(MOZ_WIDGET_GONK) CompositorOGL* compositor = static_cast<CompositorOGL*>(mCompositor.get()); nsScreenGonk* screen = static_cast<nsWindow*>(mCompositor->GetWidget())->GetScreen(); if (!screen->IsPrimaryScreen()) { // Only primary screen support mirroring return; } nsWindow* mirrorScreenWidget = screen->GetMirroringWidget(); if (!mirrorScreenWidget) { // No mirroring return; } nsScreenGonk* mirrorScreen = mirrorScreenWidget->GetScreen(); if (!mirrorScreen->GetTopWindows().IsEmpty()) { return; } EGLSurface surface = mirrorScreen->GetEGLSurface(); if (surface == LOCAL_EGL_NO_SURFACE) { // Create GLContext nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateForWindow(mirrorScreenWidget); mirrorScreenWidget->SetNativeData(NS_NATIVE_OPENGL_CONTEXT, reinterpret_cast<uintptr_t>(gl.get())); surface = mirrorScreen->GetEGLSurface(); if (surface == LOCAL_EGL_NO_SURFACE) { // Failed to create EGLSurface return; } } GLContext* gl = compositor->gl(); GLContextEGL* egl = GLContextEGL::Cast(gl); const IntSize windowSize = mirrorScreen->GetNaturalBounds().Size(); #endif if ((windowSize.width <= 0) || (windowSize.height <= 0)) { return; } ScreenRotation rotation = compositor->GetScreenRotation(); const int actualWidth = windowSize.width; const int actualHeight = windowSize.height; const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize(); const nsIntRect originalRect = nsIntRect(0, 0, originalSize.width, originalSize.height); int pageWidth = originalSize.width; int pageHeight = originalSize.height; if (rotation == ROTATION_90 || rotation == ROTATION_270) { pageWidth = originalSize.height; pageHeight = originalSize.width; } float scale = 1.0; if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) { const float scaleWidth = (float)actualWidth / (float)pageWidth; const float scaleHeight = (float)actualHeight / (float)pageHeight; scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; } const gfx::IntSize actualSize(actualWidth, actualHeight); ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize); const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0); ScopedContextSurfaceOverride overrideSurface(egl, surface); Matrix viewMatrix = ComputeTransformForRotation(originalRect, rotation); viewMatrix.Invert(); // unrotate viewMatrix.PostScale(scale, scale); viewMatrix.PostTranslate(offset.x, offset.y); Matrix4x4 matrix = Matrix4x4::From2D(viewMatrix); mRoot->ComputeEffectiveTransforms(matrix); nsIntRegion opaque; ApplyOcclusionCulling(mRoot, opaque); nsIntRegion invalid; Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight); Rect rect, actualBounds; mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds); // The Java side of Fennec sets a scissor rect that accounts for // chrome such as the URL bar. Override that so that the entire frame buffer // is cleared. ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight); egl->fClearColor(0.0, 0.0, 0.0, 0.0); egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT); const IntRect clipRect = IntRect(0, 0, actualWidth, actualHeight); RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect)); RootLayer()->RenderLayer(clipRect); mCompositor->EndFrame(); mCompositor->SetDispAcquireFence(mRoot); // Call after EndFrame() #ifdef MOZ_WIDGET_GONK nsRefPtr<Composer2D> composer2D; composer2D = mCompositor->GetWidget()->GetComposer2D(); if (composer2D) { composer2D->Render(mirrorScreenWidget); } #endif }
const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() { float scale = mFrameMetrics.mResolution.width; nsIntRect viewport = mFrameMetrics.mViewport; viewport.ScaleRoundIn(1 / scale); #ifdef USE_LARGER_DISPLAYPORT const float SIZE_MULTIPLIER = 2.0f; nsIntPoint scrollOffset = mFrameMetrics.mViewportScrollOffset; gfx::Rect contentRect = mFrameMetrics.mCSSContentRect; // Paint a larger portion of the screen than just what we can see. This makes // it less likely that we'll checkerboard when panning around and Gecko hasn't // repainted yet. float desiredWidth = viewport.width * SIZE_MULTIPLIER, desiredHeight = viewport.height * SIZE_MULTIPLIER; // The displayport is relative to the current scroll offset. Here's a little // diagram to make it easier to see: // // - - - - // | | // ************* // * | | * // - -*- @------ -*- - // | * |=====| * | // * |=====| * // | * |=====| * | // - -*- ------- -*- - // * | | * // ************* // | | // - - - - // // The full --- area with === inside it is the actual viewport rect, the *** area // is the displayport, and the - - - area is an imaginary additional page on all 4 // borders of the actual page. Notice that the displayport intersects half-way with // each of the imaginary extra pages. The @ symbol at the top left of the // viewport marks the current scroll offset. From the @ symbol to the far left // and far top, it is clear that this distance is 1/4 of the displayport's // height/width dimension. gfx::Rect displayPort(-desiredWidth / 4, -desiredHeight / 4, desiredWidth, desiredHeight); // Check if the desired boundaries go over the CSS page rect along the top or // left. If they do, shift them to the right or down. float oldDisplayPortX = displayPort.x, oldDisplayPortY = displayPort.y; if (displayPort.X() + scrollOffset.x < contentRect.X()) displayPort.x = contentRect.X() - scrollOffset.x; if (displayPort.Y() + scrollOffset.y < contentRect.Y()) displayPort.y = contentRect.Y() - scrollOffset.y; // We don't need to paint the extra area that was going to overlap with the // content rect. Subtract out this extra width or height. displayPort.width -= displayPort.x - oldDisplayPortX; displayPort.height -= displayPort.y - oldDisplayPortY; // Check if the desired boundaries go over the CSS page rect along the right // or bottom. If they do, subtract out some height or width such that they // perfectly align with the end of the CSS page rect. if (displayPort.XMost() + scrollOffset.x > contentRect.XMost()) displayPort.width = NS_MAX(0.0f, contentRect.XMost() - (displayPort.X() + scrollOffset.x)); if (displayPort.YMost() + scrollOffset.y > contentRect.YMost()) displayPort.height = NS_MAX(0.0f, contentRect.YMost() - (displayPort.Y() + scrollOffset.y)); return nsIntRect(NS_lround(displayPort.X()), NS_lround(displayPort.Y()), NS_lround(displayPort.Width()), NS_lround(displayPort.Height())); #else return nsIntRect(0, 0, NS_lround(viewport.Width()), NS_lround(viewport.Height())); #endif }
nsresult Downscaler::BeginFrame(const nsIntSize& aOriginalSize, const Maybe<nsIntRect>& aFrameRect, uint8_t* aOutputBuffer, bool aHasAlpha, bool aFlipVertically /* = false */) { MOZ_ASSERT(aOutputBuffer); MOZ_ASSERT(mTargetSize != aOriginalSize, "Created a downscaler, but not downscaling?"); MOZ_ASSERT(mTargetSize.width <= aOriginalSize.width, "Created a downscaler, but width is larger"); MOZ_ASSERT(mTargetSize.height <= aOriginalSize.height, "Created a downscaler, but height is larger"); MOZ_ASSERT(aOriginalSize.width > 0 && aOriginalSize.height > 0, "Invalid original size"); mFrameRect = aFrameRect.valueOr(nsIntRect(nsIntPoint(), aOriginalSize)); MOZ_ASSERT(mFrameRect.x >= 0 && mFrameRect.y >= 0 && mFrameRect.width >= 0 && mFrameRect.height >= 0, "Frame rect must have non-negative components"); MOZ_ASSERT(nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height) .Contains(mFrameRect), "Frame rect must fit inside image"); MOZ_ASSERT_IF(!nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height) .IsEqualEdges(mFrameRect), aHasAlpha); mOriginalSize = aOriginalSize; mScale = gfxSize(double(mOriginalSize.width) / mTargetSize.width, double(mOriginalSize.height) / mTargetSize.height); mOutputBuffer = aOutputBuffer; mHasAlpha = aHasAlpha; mFlipVertically = aFlipVertically; ReleaseWindow(); auto resizeMethod = skia::ImageOperations::RESIZE_LANCZOS3; skia::resize::ComputeFilters(resizeMethod, mOriginalSize.width, mTargetSize.width, 0, mTargetSize.width, mXFilter.get()); skia::resize::ComputeFilters(resizeMethod, mOriginalSize.height, mTargetSize.height, 0, mTargetSize.height, mYFilter.get()); // Allocate the buffer, which contains scanlines of the original image. // pad by 15 to handle overreads by the simd code mRowBuffer.reset(new (fallible) uint8_t[mOriginalSize.width * sizeof(uint32_t) + 15]); if (MOZ_UNLIKELY(!mRowBuffer)) { return NS_ERROR_OUT_OF_MEMORY; } // Allocate the window, which contains horizontally downscaled scanlines. (We // can store scanlines which are already downscale because our downscaling // filter is separable.) mWindowCapacity = mYFilter->max_filter(); mWindow.reset(new (fallible) uint8_t*[mWindowCapacity]); if (MOZ_UNLIKELY(!mWindow)) { return NS_ERROR_OUT_OF_MEMORY; } bool anyAllocationFailed = false; // pad by 15 to handle overreads by the simd code const int rowSize = mTargetSize.width * sizeof(uint32_t) + 15; for (int32_t i = 0; i < mWindowCapacity; ++i) { mWindow[i] = new (fallible) uint8_t[rowSize]; anyAllocationFailed = anyAllocationFailed || mWindow[i] == nullptr; } if (MOZ_UNLIKELY(anyAllocationFailed)) { // We intentionally iterate through the entire array even if an allocation // fails, to ensure that all the pointers in it are either valid or nullptr. // That in turn ensures that ReleaseWindow() can clean up correctly. return NS_ERROR_OUT_OF_MEMORY; } ResetForNextProgressivePass(); return NS_OK; }
void TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer, const nsIntRegion& aValidRegion, EffectChain& aEffectChain, float aOpacity, const gfx::Filter& aFilter, const gfx::Rect& aClipRect, const nsIntRegion& aMaskRegion, nsIntRect aVisibleRect, gfx::Matrix4x4 aTransform) { if (!mCompositor) { NS_WARNING("Can't render tiled content host - no compositor"); return; } float resolution = aLayerBuffer.GetResolution(); gfx::Size layerScale(1, 1); // We assume that the current frame resolution is the one used in our primary // layer buffer. Compensate for a changing frame resolution. if (aLayerBuffer.GetFrameResolution() != mVideoMemoryTiledBuffer.GetFrameResolution()) { const CSSToScreenScale& layerResolution = aLayerBuffer.GetFrameResolution(); const CSSToScreenScale& localResolution = mVideoMemoryTiledBuffer.GetFrameResolution(); layerScale.width = layerScale.height = layerResolution.scale / localResolution.scale; aVisibleRect.ScaleRoundOut(layerScale.width, layerScale.height); } aTransform.Scale(1/(resolution * layerScale.width), 1/(resolution * layerScale.height), 1); uint32_t rowCount = 0; uint32_t tileX = 0; for (int32_t x = aVisibleRect.x; x < aVisibleRect.x + aVisibleRect.width;) { rowCount++; int32_t tileStartX = aLayerBuffer.GetTileStart(x); int32_t w = aLayerBuffer.GetScaledTileLength() - tileStartX; if (x + w > aVisibleRect.x + aVisibleRect.width) { w = aVisibleRect.x + aVisibleRect.width - x; } int tileY = 0; for (int32_t y = aVisibleRect.y; y < aVisibleRect.y + aVisibleRect.height;) { int32_t tileStartY = aLayerBuffer.GetTileStart(y); int32_t h = aLayerBuffer.GetScaledTileLength() - tileStartY; if (y + h > aVisibleRect.y + aVisibleRect.height) { h = aVisibleRect.y + aVisibleRect.height - y; } TiledTexture tileTexture = aLayerBuffer. GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x), aLayerBuffer.RoundDownToTileEdge(y))); if (tileTexture != aLayerBuffer.GetPlaceholderTile()) { nsIntRegion tileDrawRegion; tileDrawRegion.And(aValidRegion, nsIntRect(x * layerScale.width, y * layerScale.height, w * layerScale.width, h * layerScale.height)); tileDrawRegion.Sub(tileDrawRegion, aMaskRegion); if (!tileDrawRegion.IsEmpty()) { tileDrawRegion.ScaleRoundOut(resolution / layerScale.width, resolution / layerScale.height); nsIntPoint tileOffset((x - tileStartX) * resolution, (y - tileStartY) * resolution); uint32_t tileSize = aLayerBuffer.GetTileLength(); RenderTile(tileTexture, aEffectChain, aOpacity, aTransform, aFilter, aClipRect, tileDrawRegion, tileOffset, nsIntSize(tileSize, tileSize)); } } tileY++; y += h; } tileX++; x += w; } gfx::Rect rect(aVisibleRect.x, aVisibleRect.y, aVisibleRect.width, aVisibleRect.height); GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTENT, rect, aClipRect, aTransform); }
ThebesLayerBuffer::PaintState ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType, PRUint32 aFlags) { PaintState result; // We need to disable rotation if we're going to be resampled when // drawing, because we might sample across the rotation boundary. bool canHaveRotation = !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)); nsIntRegion validRegion = aLayer->GetValidRegion(); ContentType contentType; nsIntRegion neededRegion; bool canReuseBuffer; nsIntRect destBufferRect; while (true) { contentType = aContentType; neededRegion = aLayer->GetVisibleRegion(); canReuseBuffer = mBuffer && BufferSizeOkFor(neededRegion.GetBounds().Size()); if (canReuseBuffer) { if (mBufferRect.Contains(neededRegion.GetBounds())) { // We don't need to adjust mBufferRect. destBufferRect = mBufferRect; } else if (neededRegion.GetBounds().Size() <= mBufferRect.Size()) { // The buffer's big enough but doesn't contain everything that's // going to be visible. We'll move it. destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size()); } else { destBufferRect = neededRegion.GetBounds(); } } else { destBufferRect = neededRegion.GetBounds(); } if ((aFlags & PAINT_WILL_RESAMPLE) && (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) || neededRegion.GetNumRects() > 1)) { // The area we add to neededRegion might not be painted opaquely contentType = gfxASurface::CONTENT_COLOR_ALPHA; // We need to validate the entire buffer, to make sure that only valid // pixels are sampled neededRegion = destBufferRect; } if (mBuffer && contentType != mBuffer->GetContentType()) { // We're effectively clearing the valid region, so we need to draw // the entire needed region now. result.mRegionToInvalidate = aLayer->GetValidRegion(); validRegion.SetEmpty(); Clear(); // Restart decision process with the cleared buffer. We can only go // around the loop one more iteration, since mBuffer is null now. continue; } break; } NS_ASSERTION(destBufferRect.Contains(neededRegion.GetBounds()), "Destination rect doesn't contain what we need to paint"); result.mRegionToDraw.Sub(neededRegion, validRegion); if (result.mRegionToDraw.IsEmpty()) return result; nsIntRect drawBounds = result.mRegionToDraw.GetBounds(); nsRefPtr<gfxASurface> destBuffer; PRUint32 bufferFlags = canHaveRotation ? ALLOW_REPEAT : 0; if (canReuseBuffer) { nsIntRect keepArea; if (keepArea.IntersectRect(destBufferRect, mBufferRect)) { // Set mBufferRotation so that the pixels currently in mBuffer // will still be rendered in the right place when mBufferRect // changes to destBufferRect. nsIntPoint newRotation = mBufferRotation + (destBufferRect.TopLeft() - mBufferRect.TopLeft()); WrapRotationAxis(&newRotation.x, mBufferRect.width); WrapRotationAxis(&newRotation.y, mBufferRect.height); NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation), "newRotation out of bounds"); PRInt32 xBoundary = destBufferRect.XMost() - newRotation.x; PRInt32 yBoundary = destBufferRect.YMost() - newRotation.y; if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) || (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) || (newRotation != nsIntPoint(0,0) && !canHaveRotation)) { // The stuff we need to redraw will wrap around an edge of the // buffer, so move the pixels we can keep into a position that // lets us redraw in just one quadrant. if (mBufferRotation == nsIntPoint(0,0)) { nsIntRect srcRect(nsIntPoint(0, 0), mBufferRect.Size()); nsIntPoint dest = mBufferRect.TopLeft() - destBufferRect.TopLeft(); mBuffer->MovePixels(srcRect, dest); result.mDidSelfCopy = true; // Don't set destBuffer; we special-case self-copies, and // just did the necessary work above. mBufferRect = destBufferRect; } else { // We can't do a real self-copy because the buffer is rotated. // So allocate a new buffer for the destination. destBufferRect = neededRegion.GetBounds(); destBuffer = CreateBuffer(contentType, destBufferRect.Size(), bufferFlags); if (!destBuffer) return result; } } else { mBufferRect = destBufferRect; mBufferRotation = newRotation; } } else { // No pixels are going to be kept. The whole visible region // will be redrawn, so we don't need to copy anything, so we don't // set destBuffer. mBufferRect = destBufferRect; mBufferRotation = nsIntPoint(0,0); } } else { // The buffer's not big enough, so allocate a new one destBuffer = CreateBuffer(contentType, destBufferRect.Size(), bufferFlags); if (!destBuffer) return result; } NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(), "If we're resampling, we need to validate the entire buffer"); // If we have no buffered data already, then destBuffer will be a fresh buffer // and we do not need to clear it below. bool isClear = mBuffer == nsnull; if (destBuffer) { if (mBuffer) { // Copy the bits nsRefPtr<gfxContext> tmpCtx = new gfxContext(destBuffer); nsIntPoint offset = -destBufferRect.TopLeft(); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); tmpCtx->Translate(gfxPoint(offset.x, offset.y)); DrawBufferWithRotation(tmpCtx, 1.0); } mBuffer = destBuffer.forget(); mBufferRect = destBufferRect; mBufferRotation = nsIntPoint(0,0); } NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0), "Rotation disabled, but we have nonzero rotation?"); nsIntRegion invalidate; invalidate.Sub(aLayer->GetValidRegion(), destBufferRect); result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate); result.mContext = GetContextForQuadrantUpdate(drawBounds); gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw); if (contentType == gfxASurface::CONTENT_COLOR_ALPHA && !isClear) { result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR); result.mContext->Paint(); result.mContext->SetOperator(gfxContext::OPERATOR_OVER); } return result; }
void LayerManagerComposite::RenderToPresentationSurface() { #ifdef MOZ_WIDGET_ANDROID nsIWidget* const widget = mCompositor->GetWidget()->RealWidget(); auto window = static_cast<ANativeWindow*>( widget->GetNativeData(NS_PRESENTATION_WINDOW)); if (!window) { return; } EGLSurface surface = widget->GetNativeData(NS_PRESENTATION_SURFACE); if (!surface) { //create surface; surface = GLContextProviderEGL::CreateEGLSurface(window); if (!surface) { return; } widget->SetNativeData(NS_PRESENTATION_SURFACE, reinterpret_cast<uintptr_t>(surface)); } CompositorOGL* compositor = mCompositor->AsCompositorOGL(); GLContext* gl = compositor->gl(); GLContextEGL* egl = GLContextEGL::Cast(gl); if (!egl) { return; } const IntSize windowSize(ANativeWindow_getWidth(window), ANativeWindow_getHeight(window)); #endif if ((windowSize.width <= 0) || (windowSize.height <= 0)) { return; } ScreenRotation rotation = compositor->GetScreenRotation(); const int actualWidth = windowSize.width; const int actualHeight = windowSize.height; const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize(); const nsIntRect originalRect = nsIntRect(0, 0, originalSize.width, originalSize.height); int pageWidth = originalSize.width; int pageHeight = originalSize.height; if (rotation == ROTATION_90 || rotation == ROTATION_270) { pageWidth = originalSize.height; pageHeight = originalSize.width; } float scale = 1.0; if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) { const float scaleWidth = (float)actualWidth / (float)pageWidth; const float scaleHeight = (float)actualHeight / (float)pageHeight; scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; } const gfx::IntSize actualSize(actualWidth, actualHeight); ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize); const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0); ScopedContextSurfaceOverride overrideSurface(egl, surface); Matrix viewMatrix = ComputeTransformForRotation(originalRect, rotation); viewMatrix.Invert(); // unrotate viewMatrix.PostScale(scale, scale); viewMatrix.PostTranslate(offset.x, offset.y); Matrix4x4 matrix = Matrix4x4::From2D(viewMatrix); mRoot->ComputeEffectiveTransforms(matrix); nsIntRegion opaque; LayerIntRegion visible; PostProcessLayers(mRoot, opaque, visible, Nothing()); nsIntRegion invalid; IntRect bounds = IntRect::Truncate(0, 0, scale * pageWidth, actualHeight); IntRect rect, actualBounds; MOZ_ASSERT(mRoot->GetOpacity() == 1); mCompositor->BeginFrame(invalid, nullptr, bounds, nsIntRegion(), &rect, &actualBounds); // The Java side of Fennec sets a scissor rect that accounts for // chrome such as the URL bar. Override that so that the entire frame buffer // is cleared. ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight); egl->fClearColor(0.0, 0.0, 0.0, 0.0); egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT); const IntRect clipRect = IntRect::Truncate(0, 0, actualWidth, actualHeight); RootLayer()->Prepare(RenderTargetIntRect::FromUnknownRect(clipRect)); RootLayer()->RenderLayer(clipRect); mCompositor->EndFrame(); }
void LayerManagerComposite::RenderDebugOverlay(const Rect& aBounds) { bool drawFps = gfxPrefs::LayersDrawFPS(); bool drawFrameCounter = gfxPrefs::DrawFrameCounter(); bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars(); TimeStamp now = TimeStamp::Now(); if (drawFps) { if (!mFPS) { mFPS = MakeUnique<FPSState>(); } float alpha = 1; #ifdef ANDROID // Draw a translation delay warning overlay int width; int border; if (!mWarnTime.IsNull() && (now - mWarnTime).ToMilliseconds() < kVisualWarningDuration) { EffectChain effects; // Black blorder border = 4; width = 6; effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(0, 0, 0, 1)); mCompositor->DrawQuad(gfx::Rect(border, border, aBounds.width - 2 * border, width), aBounds, effects, alpha, gfx::Matrix4x4()); mCompositor->DrawQuad(gfx::Rect(border, aBounds.height - border - width, aBounds.width - 2 * border, width), aBounds, effects, alpha, gfx::Matrix4x4()); mCompositor->DrawQuad(gfx::Rect(border, border + width, width, aBounds.height - 2 * border - width * 2), aBounds, effects, alpha, gfx::Matrix4x4()); mCompositor->DrawQuad(gfx::Rect(aBounds.width - border - width, border + width, width, aBounds.height - 2 * border - 2 * width), aBounds, effects, alpha, gfx::Matrix4x4()); // Content border = 5; width = 4; effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(1, 1.f - mWarningLevel, 0, 1)); mCompositor->DrawQuad(gfx::Rect(border, border, aBounds.width - 2 * border, width), aBounds, effects, alpha, gfx::Matrix4x4()); mCompositor->DrawQuad(gfx::Rect(border, aBounds.height - border - width, aBounds.width - 2 * border, width), aBounds, effects, alpha, gfx::Matrix4x4()); mCompositor->DrawQuad(gfx::Rect(border, border + width, width, aBounds.height - 2 * border - width * 2), aBounds, effects, alpha, gfx::Matrix4x4()); mCompositor->DrawQuad(gfx::Rect(aBounds.width - border - width, border + width, width, aBounds.height - 2 * border - 2 * width), aBounds, effects, alpha, gfx::Matrix4x4()); SetDebugOverlayWantsNextFrame(true); } #endif float fillRatio = mCompositor->GetFillRatio(); mFPS->DrawFPS(now, drawFrameColorBars ? 10 : 1, 2, unsigned(fillRatio), mCompositor); if (mUnusedApzTransformWarning) { // If we have an unused APZ transform on this composite, draw a 20x20 red box // in the top-right corner EffectChain effects; effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(1, 0, 0, 1)); mCompositor->DrawQuad(gfx::Rect(aBounds.width - 20, 0, aBounds.width, 20), aBounds, effects, alpha, gfx::Matrix4x4()); mUnusedApzTransformWarning = false; SetDebugOverlayWantsNextFrame(true); } // Each frame is invalidate by the previous frame for simplicity AddInvalidRegion(nsIntRect(0, 0, 256, 256)); } else { mFPS = nullptr; } if (drawFrameColorBars) { gfx::Rect sideRect(0, 0, 10, aBounds.height); EffectChain effects; effects.mPrimaryEffect = new EffectSolidColor(gfxUtils::GetColorForFrameNumber(sFrameCount)); mCompositor->DrawQuad(sideRect, sideRect, effects, 1.0, gfx::Matrix4x4()); // Each frame is invalidate by the previous frame for simplicity AddInvalidRegion(nsIntRect(0, 0, sideRect.width, sideRect.height)); } #ifdef MOZ_PROFILING if (drawFrameCounter) { profiler_set_frame_number(sFrameCount); const char* qr = sQRCodeTable[sFrameCount%256]; int size = 21; int padding = 2; float opacity = 1.0; const uint16_t bitWidth = 5; gfx::Rect clip(0,0, bitWidth*640, bitWidth*640); // Draw the white squares at once gfx::Color bitColor(1.0, 1.0, 1.0, 1.0); EffectChain effects; effects.mPrimaryEffect = new EffectSolidColor(bitColor); int totalSize = (size + padding * 2) * bitWidth; mCompositor->DrawQuad(gfx::Rect(0, 0, totalSize, totalSize), clip, effects, opacity, gfx::Matrix4x4()); // Draw a black square for every bit set in qr[index] effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(0, 0, 0, 1.0)); for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { // Select the right bit from the binary encoding int currBit = 128 >> ((x + y * 21) % 8); int i = (x + y * 21) / 8; if (qr[i] & currBit) { mCompositor->DrawQuad(gfx::Rect(bitWidth * (x + padding), bitWidth * (y + padding), bitWidth, bitWidth), clip, effects, opacity, gfx::Matrix4x4()); } } } // Each frame is invalidate by the previous frame for simplicity AddInvalidRegion(nsIntRect(0, 0, 256, 256)); } #endif if (drawFrameColorBars || drawFrameCounter) { // We intentionally overflow at 2^16. sFrameCount++; } }
nsresult nsRawReader::ReadMetadata(nsVideoInfo* aInfo) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); nsMediaStream* stream = mDecoder->GetCurrentStream(); NS_ASSERTION(stream, "Decoder has no media stream"); if (!ReadFromStream(stream, reinterpret_cast<PRUint8*>(&mMetadata), sizeof(mMetadata))) return NS_ERROR_FAILURE; // Validate the header if (!(mMetadata.headerPacketID == 0 /* Packet ID of 0 for the header*/ && mMetadata.codecID == RAW_ID /* "YUV" */ && mMetadata.majorVersion == 0 && mMetadata.minorVersion == 1)) return NS_ERROR_FAILURE; PRUint32 dummy; if (!MulOverflow32(mMetadata.frameWidth, mMetadata.frameHeight, dummy)) return NS_ERROR_FAILURE; if (mMetadata.aspectDenominator == 0 || mMetadata.framerateDenominator == 0) return NS_ERROR_FAILURE; // Invalid data // Determine and verify frame display size. float pixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) / mMetadata.aspectDenominator; nsIntSize display(mMetadata.frameWidth, mMetadata.frameHeight); ScaleDisplayByAspectRatio(display, pixelAspectRatio); mPicture = nsIntRect(0, 0, mMetadata.frameWidth, mMetadata.frameHeight); nsIntSize frameSize(mMetadata.frameWidth, mMetadata.frameHeight); if (!nsVideoInfo::ValidateVideoRegion(frameSize, mPicture, display)) { // Video track's frame sizes will overflow. Fail. return NS_ERROR_FAILURE; } mInfo.mHasVideo = true; mInfo.mHasAudio = false; mInfo.mDisplay = display; mFrameRate = static_cast<float>(mMetadata.framerateNumerator) / mMetadata.framerateDenominator; // Make some sanity checks if (mFrameRate > 45 || mFrameRate == 0 || pixelAspectRatio == 0 || mMetadata.frameWidth > 2000 || mMetadata.frameHeight > 2000 || mMetadata.chromaChannelBpp != 4 || mMetadata.lumaChannelBpp != 8 || mMetadata.colorspace != 1 /* 4:2:0 */) return NS_ERROR_FAILURE; mFrameSize = mMetadata.frameWidth * mMetadata.frameHeight * (mMetadata.lumaChannelBpp + mMetadata.chromaChannelBpp) / 8.0 + sizeof(nsRawPacketHeader); PRInt64 length = stream->GetLength(); if (length != -1) { mozilla::ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor()); mDecoder->GetStateMachine()->SetDuration(USECS_PER_S * (length - sizeof(nsRawVideoHeader)) / (mFrameSize * mFrameRate)); } *aInfo = mInfo; return NS_OK; }
nsresult imgFrame::ReinitForDecoder(const nsIntSize& aImageSize, const nsIntRect& aRect, SurfaceFormat aFormat, uint8_t aPaletteDepth /* = 0 */, bool aNonPremult /* = false */) { MonitorAutoLock lock(mMonitor); if (mDecoded.x != 0 || mDecoded.y != 0 || mDecoded.width != 0 || mDecoded.height != 0) { MOZ_ASSERT_UNREACHABLE("Shouldn't reinit after write"); return NS_ERROR_FAILURE; } if (mAborted) { MOZ_ASSERT_UNREACHABLE("Shouldn't reinit if aborted"); return NS_ERROR_FAILURE; } if (mLockCount < 1) { MOZ_ASSERT_UNREACHABLE("Shouldn't reinit unless locked"); return NS_ERROR_FAILURE; } // Restore everything (except mLockCount, which we need to keep) to how it was // when we were first created. // XXX(seth): This is probably a little excessive, but I want to be *really* // sure that nothing got missed. mDecoded = nsIntRect(0, 0, 0, 0); mTimeout = 100; mDisposalMethod = DisposalMethod::NOT_SPECIFIED; mBlendMethod = BlendMethod::OVER; mHasNoAlpha = false; mAborted = false; mPaletteDepth = 0; mNonPremult = false; mSinglePixel = false; mCompositingFailed = false; mOptimizable = false; mImageSize = IntSize(); mSize = IntSize(); mOffset = nsIntPoint(); mSinglePixelColor = Color(); // Release all surfaces. mImageSurface = nullptr; mOptSurface = nullptr; mVBuf = nullptr; mVBufPtr = nullptr; free(mPalettedImageData); mPalettedImageData = nullptr; // Reinitialize. nsresult rv = InitForDecoder(aImageSize, aRect, aFormat, aPaletteDepth, aNonPremult); if (NS_FAILED(rv)) { return rv; } // We were locked before; perform the same actions we would've performed when // we originally got locked. if (mImageSurface) { mVBufPtr = mVBuf; return NS_OK; } if (!mPalettedImageData) { MOZ_ASSERT_UNREACHABLE("We got optimized somehow during reinit"); return NS_ERROR_FAILURE; } // Paletted images don't have surfaces, so there's nothing to do. return NS_OK; }
void ContentHostBase::Composite(EffectChain& aEffectChain, float aOpacity, const gfx::Matrix4x4& aTransform, const Filter& aFilter, const Rect& aClipRect, const nsIntRegion* aVisibleRegion, TiledLayerProperties* aLayerProperties) { NS_ASSERTION(aVisibleRegion, "Requires a visible region"); AutoLockTextureHost lock(mTextureHost); AutoLockTextureHost lockOnWhite(mTextureHostOnWhite); if (!mTextureHost || !lock.IsValid() || !lockOnWhite.IsValid()) { return; } RefPtr<NewTextureSource> source = mTextureHost->GetTextureSources(); RefPtr<NewTextureSource> sourceOnWhite = mTextureHostOnWhite ? mTextureHostOnWhite->GetTextureSources() : nullptr; if (!source) { return; } RefPtr<TexturedEffect> effect = CreateTexturedEffect(source, sourceOnWhite, aFilter); aEffectChain.mPrimaryEffect = effect; nsIntRegion tmpRegion; const nsIntRegion* renderRegion; if (PaintWillResample()) { // If we're resampling, then the texture image will contain exactly the // entire visible region's bounds, and we should draw it all in one quad // to avoid unexpected aliasing. tmpRegion = aVisibleRegion->GetBounds(); renderRegion = &tmpRegion; } else { renderRegion = aVisibleRegion; } nsIntRegion region(*renderRegion); nsIntPoint origin = GetOriginOffset(); // translate into TexImage space, buffer origin might not be at texture (0,0) region.MoveBy(-origin); // Figure out the intersecting draw region gfx::IntSize texSize = source->GetSize(); nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height); textureRect.MoveBy(region.GetBounds().TopLeft()); nsIntRegion subregion; subregion.And(region, textureRect); if (subregion.IsEmpty()) { // Region is empty, nothing to draw return; } nsIntRegion screenRects; nsIntRegion regionRects; // Collect texture/screen coordinates for drawing nsIntRegionRectIterator iter(subregion); while (const nsIntRect* iterRect = iter.Next()) { nsIntRect regionRect = *iterRect; nsIntRect screenRect = regionRect; screenRect.MoveBy(origin); screenRects.Or(screenRects, screenRect); regionRects.Or(regionRects, regionRect); } TileIterator* tileIter = source->AsTileIterator(); TileIterator* iterOnWhite = nullptr; if (tileIter) { tileIter->BeginTileIteration(); } if (mTextureHostOnWhite) { iterOnWhite = sourceOnWhite->AsTileIterator(); MOZ_ASSERT(!tileIter || tileIter->GetTileCount() == iterOnWhite->GetTileCount(), "Tile count mismatch on component alpha texture"); if (iterOnWhite) { iterOnWhite->BeginTileIteration(); } } bool usingTiles = (tileIter && tileIter->GetTileCount() > 1); do { if (iterOnWhite) { MOZ_ASSERT(iterOnWhite->GetTileRect() == tileIter->GetTileRect(), "component alpha textures should be the same size."); } nsIntRect texRect = tileIter ? tileIter->GetTileRect() : nsIntRect(0, 0, texSize.width, texSize.height); // Draw texture. If we're using tiles, we do repeating manually, as texture // repeat would cause each individual tile to repeat instead of the // compound texture as a whole. This involves drawing at most 4 sections, // 2 for each axis that has texture repeat. for (int y = 0; y < (usingTiles ? 2 : 1); y++) { for (int x = 0; x < (usingTiles ? 2 : 1); x++) { nsIntRect currentTileRect(texRect); currentTileRect.MoveBy(x * texSize.width, y * texSize.height); nsIntRegionRectIterator screenIter(screenRects); nsIntRegionRectIterator regionIter(regionRects); const nsIntRect* screenRect; const nsIntRect* regionRect; while ((screenRect = screenIter.Next()) && (regionRect = regionIter.Next())) { nsIntRect tileScreenRect(*screenRect); nsIntRect tileRegionRect(*regionRect); // When we're using tiles, find the intersection between the tile // rect and this region rect. Tiling is then handled by the // outer for-loops and modifying the tile rect. if (usingTiles) { tileScreenRect.MoveBy(-origin); tileScreenRect = tileScreenRect.Intersect(currentTileRect); tileScreenRect.MoveBy(origin); if (tileScreenRect.IsEmpty()) continue; tileRegionRect = regionRect->Intersect(currentTileRect); tileRegionRect.MoveBy(-currentTileRect.TopLeft()); } gfx::Rect rect(tileScreenRect.x, tileScreenRect.y, tileScreenRect.width, tileScreenRect.height); effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width, Float(tileRegionRect.y) / texRect.height, Float(tileRegionRect.width) / texRect.width, Float(tileRegionRect.height) / texRect.height); GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform); if (usingTiles) { DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT | DIAGNOSTIC_BIGIMAGE; diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect, aTransform); } } } } if (iterOnWhite) { iterOnWhite->NextTile(); } } while (usingTiles && tileIter->NextTile()); if (tileIter) { tileIter->EndTileIteration(); } if (iterOnWhite) { iterOnWhite->EndTileIteration(); } DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT; diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; GetCompositor()->DrawDiagnostics(diagnostics, *aVisibleRegion, aClipRect, aTransform); }
bool TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface, nsIntRegion* aDestRegion, gfx::IntPoint* aSrcOffset) { GLContext *gl = mCompositor->gl(); MOZ_ASSERT(gl); if (!gl) { NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext"); return false; } if (!aSurface) { gfxCriticalError() << "Invalid surface for OGL update"; return false; } MOZ_ASSERT(aSurface); IntSize size = aSurface->GetSize(); if (!mTexImage || (mTexImage->GetSize() != size && !aSrcOffset) || mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) { if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) { GLint maxTextureSize; gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize); if (size.width > maxTextureSize || size.height > maxTextureSize) { NS_WARNING("Texture exceeds maximum texture size, refusing upload"); return false; } // Explicitly use CreateBasicTextureImage instead of CreateTextureImage, // because CreateTextureImage might still choose to create a tiled // texture image. mTexImage = CreateBasicTextureImage(gl, size, gfx::ContentForFormat(aSurface->GetFormat()), LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags), SurfaceFormatToImageFormat(aSurface->GetFormat())); } else { // XXX - clarify which size we want to use. IncrementalContentHost will // require the size of the destination surface to be different from // the size of aSurface. // See bug 893300 (tracks the implementation of ContentHost for new textures). mTexImage = CreateTextureImage(gl, size, gfx::ContentForFormat(aSurface->GetFormat()), LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags), SurfaceFormatToImageFormat(aSurface->GetFormat())); } ClearCachedFilter(); if (aDestRegion && !aSrcOffset && !aDestRegion->IsEqual(nsIntRect(0, 0, size.width, size.height))) { // UpdateFromDataSource will ignore our specified aDestRegion since the texture // hasn't been allocated with glTexImage2D yet. Call Resize() to force the // allocation (full size, but no upload), and then we'll only upload the pixels // we care about below. mTexImage->Resize(size); } } mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset); if (mTexImage->InUpdate()) { mTexImage->EndUpdate(); } return true; }
nsIntRect DeprecatedTextureHostShmemD3D11::GetTileRect() { IntRect rect = GetTileRect(mCurrentTile); return nsIntRect(rect.x, rect.y, rect.width, rect.height); }
void nsJPEGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount) { mSegment = (const JOCTET*)aBuffer; mSegmentLen = aCount; MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!"); // Return here if there is a fatal error within libjpeg. nsresult error_code; // This cast to nsresult makes sense because setjmp() returns whatever we // passed to longjmp(), which was actually an nsresult. if ((error_code = (nsresult)setjmp(mErr.setjmp_buffer)) != NS_OK) { if (error_code == NS_ERROR_FAILURE) { PostDataError(); // Error due to corrupt stream - return NS_OK and consume silently // so that ImageLib doesn't throw away a partial image load mState = JPEG_SINK_NON_JPEG_TRAILER; MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (setjmp returned NS_ERROR_FAILURE)")); return; } else { // Error due to reasons external to the stream (probably out of // memory) - let ImageLib attempt to clean up, even though // mozilla is seconds away from falling flat on its face. PostDecoderError(error_code); mState = JPEG_ERROR; MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (setjmp returned an error)")); return; } } MOZ_LOG(GetJPEGLog(), LogLevel::Debug, ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this)); switch (mState) { case JPEG_HEADER: { LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_HEADER" " case"); // Step 3: read file parameters with jpeg_read_header() if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) { MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (JPEG_SUSPENDED)")); return; // I/O suspension } // If we have a sample size specified for -moz-sample-size, use it. if (mSampleSize > 0) { mInfo.scale_num = 1; mInfo.scale_denom = mSampleSize; } // Used to set up image size so arrays can be allocated jpeg_calc_output_dimensions(&mInfo); // Post our size to the superclass PostSize(mInfo.output_width, mInfo.output_height, ReadOrientationFromEXIF()); if (HasError()) { // Setting the size led to an error. mState = JPEG_ERROR; return; } // If we're doing a metadata decode, we're done. if (IsMetadataDecode()) { return; } // We're doing a full decode. if (mCMSMode != eCMSMode_Off && (mInProfile = GetICCProfile(mInfo)) != nullptr) { uint32_t profileSpace = qcms_profile_get_color_space(mInProfile); bool mismatch = false; #ifdef DEBUG_tor fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace); #endif switch (mInfo.jpeg_color_space) { case JCS_GRAYSCALE: if (profileSpace == icSigRgbData) { mInfo.out_color_space = JCS_RGB; } else if (profileSpace != icSigGrayData) { mismatch = true; } break; case JCS_RGB: if (profileSpace != icSigRgbData) { mismatch = true; } break; case JCS_YCbCr: if (profileSpace == icSigRgbData) { mInfo.out_color_space = JCS_RGB; } else { // qcms doesn't support ycbcr mismatch = true; } break; case JCS_CMYK: case JCS_YCCK: // qcms doesn't support cmyk mismatch = true; break; default: mState = JPEG_ERROR; PostDataError(); MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (unknown colorpsace (1))")); return; } if (!mismatch) { qcms_data_type type; switch (mInfo.out_color_space) { case JCS_GRAYSCALE: type = QCMS_DATA_GRAY_8; break; case JCS_RGB: type = QCMS_DATA_RGB_8; break; default: mState = JPEG_ERROR; PostDataError(); MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (unknown colorpsace (2))")); return; } #if 0 // We don't currently support CMYK profiles. The following // code dealt with lcms types. Add something like this // back when we gain support for CMYK. // Adobe Photoshop writes YCCK/CMYK files with inverted data if (mInfo.out_color_space == JCS_CMYK) { type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0); } #endif if (gfxPlatform::GetCMSOutputProfile()) { // Calculate rendering intent. int intent = gfxPlatform::GetRenderingIntent(); if (intent == -1) { intent = qcms_profile_get_rendering_intent(mInProfile); } // Create the color management transform. mTransform = qcms_transform_create(mInProfile, type, gfxPlatform::GetCMSOutputProfile(), QCMS_DATA_RGB_8, (qcms_intent)intent); } } else { #ifdef DEBUG_tor fprintf(stderr, "ICM profile colorspace mismatch\n"); #endif } } if (!mTransform) { switch (mInfo.jpeg_color_space) { case JCS_GRAYSCALE: case JCS_RGB: case JCS_YCbCr: // if we're not color managing we can decode directly to // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB if (mCMSMode != eCMSMode_All) { mInfo.out_color_space = MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB; mInfo.out_color_components = 4; } else { mInfo.out_color_space = JCS_RGB; } break; case JCS_CMYK: case JCS_YCCK: // libjpeg can convert from YCCK to CMYK, but not to RGB mInfo.out_color_space = JCS_CMYK; break; default: mState = JPEG_ERROR; PostDataError(); MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (unknown colorpsace (3))")); return; } } // Don't allocate a giant and superfluous memory buffer // when not doing a progressive decode. mInfo.buffered_image = mDecodeStyle == PROGRESSIVE && jpeg_has_multiple_scans(&mInfo); MOZ_ASSERT(!mImageData, "Already have a buffer allocated?"); nsIntSize targetSize = mDownscaler ? mDownscaler->TargetSize() : GetSize(); nsresult rv = AllocateFrame(0, targetSize, nsIntRect(nsIntPoint(), targetSize), gfx::SurfaceFormat::B8G8R8A8); if (NS_FAILED(rv)) { mState = JPEG_ERROR; MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (could not initialize image frame)")); return; } MOZ_ASSERT(mImageData, "Should have a buffer now"); if (mDownscaler) { nsresult rv = mDownscaler->BeginFrame(GetSize(), mImageData, /* aHasAlpha = */ false); if (NS_FAILED(rv)) { mState = JPEG_ERROR; return; } } MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, (" JPEGDecoderAccounting: nsJPEGDecoder::" "Write -- created image frame with %ux%u pixels", mInfo.output_width, mInfo.output_height)); mState = JPEG_START_DECOMPRESS; } case JPEG_START_DECOMPRESS: { LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering" " JPEG_START_DECOMPRESS case"); // Step 4: set parameters for decompression // FIXME -- Should reset dct_method and dither mode // for final pass of progressive JPEG mInfo.dct_method = JDCT_ISLOW; mInfo.dither_mode = JDITHER_FS; mInfo.do_fancy_upsampling = TRUE; mInfo.enable_2pass_quant = FALSE; mInfo.do_block_smoothing = TRUE; // Step 5: Start decompressor if (jpeg_start_decompress(&mInfo) == FALSE) { MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (I/O suspension after jpeg_start_decompress())")); return; // I/O suspension } // If this is a progressive JPEG ... mState = mInfo.buffered_image ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL; } case JPEG_DECOMPRESS_SEQUENTIAL: { if (mState == JPEG_DECOMPRESS_SEQUENTIAL) { LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- " "JPEG_DECOMPRESS_SEQUENTIAL case"); bool suspend; OutputScanlines(&suspend); if (suspend) { MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)")); return; // I/O suspension } // If we've completed image output ... NS_ASSERTION(mInfo.output_scanline == mInfo.output_height, "We didn't process all of the data!"); mState = JPEG_DONE; } } case JPEG_DECOMPRESS_PROGRESSIVE: { if (mState == JPEG_DECOMPRESS_PROGRESSIVE) { LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case"); int status; do { status = jpeg_consume_input(&mInfo); } while ((status != JPEG_SUSPENDED) && (status != JPEG_REACHED_EOI)); for (;;) { if (mInfo.output_scanline == 0) { int scan = mInfo.input_scan_number; // if we haven't displayed anything yet (output_scan_number==0) // and we have enough data for a complete scan, force output // of the last full scan if ((mInfo.output_scan_number == 0) && (scan > 1) && (status != JPEG_REACHED_EOI)) scan--; if (!jpeg_start_output(&mInfo, scan)) { MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (I/O suspension after jpeg_start_output() -" " PROGRESSIVE)")); return; // I/O suspension } } if (mInfo.output_scanline == 0xffffff) { mInfo.output_scanline = 0; } bool suspend; OutputScanlines(&suspend); if (suspend) { if (mInfo.output_scanline == 0) { // didn't manage to read any lines - flag so we don't call // jpeg_start_output() multiple times for the same scan mInfo.output_scanline = 0xffffff; } MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)")); return; // I/O suspension } if (mInfo.output_scanline == mInfo.output_height) { if (!jpeg_finish_output(&mInfo)) { MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (I/O suspension after jpeg_finish_output() -" " PROGRESSIVE)")); return; // I/O suspension } if (jpeg_input_complete(&mInfo) && (mInfo.input_scan_number == mInfo.output_scan_number)) break; mInfo.output_scanline = 0; if (mDownscaler) { mDownscaler->ResetForNextProgressivePass(); } } } mState = JPEG_DONE; } } case JPEG_DONE: { LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::ProcessData -- entering" " JPEG_DONE case"); // Step 7: Finish decompression if (jpeg_finish_decompress(&mInfo) == FALSE) { MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (I/O suspension after jpeg_finish_decompress() - DONE)")); return; // I/O suspension } mState = JPEG_SINK_NON_JPEG_TRAILER; // we're done dude break; } case JPEG_SINK_NON_JPEG_TRAILER: MOZ_LOG(GetJPEGLog(), LogLevel::Debug, ("[this=%p] nsJPEGDecoder::ProcessData -- entering" " JPEG_SINK_NON_JPEG_TRAILER case\n", this)); break; case JPEG_ERROR: MOZ_ASSERT(false, "Should always return immediately after error and not re-enter " "decoder"); } MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug, ("} (end of function)")); return; }
bool HwcComposer2D::PrepareLayerList(Layer* aLayer, const nsIntRect& aClip, const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform) { // NB: we fall off this path whenever there are container layers // that require intermediate surfaces. That means all the // GetEffective*() coordinates are relative to the framebuffer. bool fillColor = false; const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); if (visibleRegion.IsEmpty()) { return true; } uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0)); #if ANDROID_VERSION < 18 if (opacity < 0xFF) { LOGD("%s Layer has planar semitransparency which is unsupported", aLayer->Name()); return false; } #endif nsIntRect clip; if (!HwcUtils::CalculateClipRect(aParentTransform * aGLWorldTransform, aLayer->GetEffectiveClipRect(), aClip, &clip)) { LOGD("%s Clip rect is empty. Skip layer", aLayer->Name()); return true; } // HWC supports only the following 2D transformations: // // Scaling via the sourceCrop and displayFrame in HwcLayer // Translation via the sourceCrop and displayFrame in HwcLayer // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags // // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes // above gfxMatrix transform; const gfx3DMatrix& transform3D = aLayer->GetEffectiveTransform(); if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) { LOGD("Layer has a 3D transform or a non-square angle rotation"); return false; } if (ContainerLayer* container = aLayer->AsContainerLayer()) { if (container->UseIntermediateSurface()) { LOGD("Container layer needs intermediate surface"); return false; } nsAutoTArray<Layer*, 12> children; container->SortChildrenBy3DZOrder(children); for (uint32_t i = 0; i < children.Length(); i++) { if (!PrepareLayerList(children[i], clip, transform, aGLWorldTransform)) { return false; } } return true; } LayerRenderState state = aLayer->GetRenderState(); nsIntSize surfaceSize; if (state.mSurface.get()) { surfaceSize = state.mSize; } else { if (aLayer->AsColorLayer() && mColorFill) { fillColor = true; } else { LOGD("%s Layer doesn't have a gralloc buffer", aLayer->Name()); return false; } } // Buffer rotation is not to be confused with the angled rotation done by a transform matrix // It's a fancy ThebesLayer feature used for scrolling if (state.BufferRotated()) { LOGD("%s Layer has a rotated buffer", aLayer->Name()); return false; } // OK! We can compose this layer with hwc. int current = mList ? mList->numHwLayers : 0; if (!mList || current >= mMaxLayerCount) { if (!ReallocLayerList() || current >= mMaxLayerCount) { LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); return false; } } nsIntRect visibleRect = visibleRegion.GetBounds(); nsIntRect bufferRect; if (fillColor) { bufferRect = nsIntRect(visibleRect); } else { if(state.mHasOwnOffset) { bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, state.mSize.width, state.mSize.height); } else { //Since the buffer doesn't have its own offset, assign the whole //surface size as its buffer bounds bufferRect = nsIntRect(0, 0, state.mSize.width, state.mSize.height); } } HwcLayer& hwcLayer = mList->hwLayers[current]; if(!HwcUtils::PrepareLayerRects(visibleRect, transform * aGLWorldTransform, clip, bufferRect, &(hwcLayer.sourceCrop), &(hwcLayer.displayFrame))) { return true; } buffer_handle_t handle = fillColor ? nullptr : state.mSurface->getNativeBuffer()->handle; hwcLayer.handle = handle; hwcLayer.flags = 0; hwcLayer.hints = 0; hwcLayer.blending = HWC_BLENDING_PREMULT; #if ANDROID_VERSION >= 18 hwcLayer.compositionType = HWC_FRAMEBUFFER; hwcLayer.acquireFenceFd = -1; hwcLayer.releaseFenceFd = -1; hwcLayer.planeAlpha = opacity; #else hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT; #endif if (!fillColor) { if (state.FormatRBSwapped()) { if (!mRBSwapSupport) { LOGD("No R/B swap support in H/W Composer"); return false; } hwcLayer.flags |= HwcUtils::HWC_FORMAT_RB_SWAP; } // Translation and scaling have been addressed in PrepareLayerRects(). // Given the above and that we checked for PreservesAxisAlignedRectangles() // the only possible transformations left to address are // square angle rotation and horizontal/vertical reflection. // // The rotation and reflection permutations total 16 but can be // reduced to 8 transformations after eliminating redundancies. // // All matrices represented here are in the form // // | xx xy | // | yx yy | // // And ignore scaling. // // Reflection is applied before rotation gfxMatrix rotation = transform * aGLWorldTransform; // Compute fuzzy zero like PreservesAxisAlignedRectangles() if (fabs(rotation.xx) < 1e-6) { if (rotation.xy < 0) { if (rotation.yx > 0) { // 90 degree rotation // // | 0 -1 | // | 1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90; LOGD("Layer rotated 90 degrees"); } else { // Horizontal reflection then 90 degree rotation // // | 0 -1 | | -1 0 | = | 0 -1 | // | 1 0 | | 0 1 | | -1 0 | // // same as vertical reflection then 270 degree rotation // // | 0 1 | | 1 0 | = | 0 -1 | // | -1 0 | | 0 -1 | | -1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H; LOGD("Layer vertically reflected then rotated 270 degrees"); } } else { if (rotation.yx < 0) { // 270 degree rotation // // | 0 1 | // | -1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_270; LOGD("Layer rotated 270 degrees"); } else { // Vertical reflection then 90 degree rotation // // | 0 1 | | -1 0 | = | 0 1 | // | -1 0 | | 0 1 | | 1 0 | // // Same as horizontal reflection then 270 degree rotation // // | 0 -1 | | 1 0 | = | 0 1 | // | 1 0 | | 0 -1 | | 1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V; LOGD("Layer horizontally reflected then rotated 270 degrees"); } } } else if (rotation.xx < 0) { if (rotation.yy > 0) { // Horizontal reflection // // | -1 0 | // | 0 1 | // hwcLayer.transform = HWC_TRANSFORM_FLIP_H; LOGD("Layer rotated 180 degrees"); } else { // 180 degree rotation // // | -1 0 | // | 0 -1 | // // Same as horizontal and vertical reflection // // | -1 0 | | 1 0 | = | -1 0 | // | 0 1 | | 0 -1 | | 0 -1 | // hwcLayer.transform = HWC_TRANSFORM_ROT_180; LOGD("Layer rotated 180 degrees"); } } else { if (rotation.yy < 0) { // Vertical reflection // // | 1 0 | // | 0 -1 | // hwcLayer.transform = HWC_TRANSFORM_FLIP_V; LOGD("Layer rotated 180 degrees"); } else { // No rotation or reflection // // | 1 0 | // | 0 1 | // hwcLayer.transform = 0; } } if (state.YFlipped()) { // Invert vertical reflection flag if it was already set hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V; } hwc_region_t region; if (visibleRegion.GetNumRects() > 1) { mVisibleRegions.push_back(HwcUtils::RectVector()); HwcUtils::RectVector* visibleRects = &(mVisibleRegions.back()); if(!HwcUtils::PrepareVisibleRegion(visibleRegion, transform * aGLWorldTransform, clip, bufferRect, visibleRects)) { return true; } region.numRects = visibleRects->size(); region.rects = &((*visibleRects)[0]); } else { region.numRects = 1; region.rects = &(hwcLayer.displayFrame); } hwcLayer.visibleRegionScreen = region; } else { hwcLayer.flags |= HwcUtils::HWC_COLOR_FILL; ColorLayer* colorLayer = aLayer->AsColorLayer(); if (colorLayer->GetColor().a < 1.0) { LOGD("Color layer has semitransparency which is unsupported"); return false; } hwcLayer.transform = colorLayer->GetColor().Packed(); } mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData())); mList->numHwLayers++; return true; }
NS_IMETHODIMP nsScriptableRegion::ContainsRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, bool *containsRect) { *containsRect = mRegion.Contains(nsIntRect(aX, aY, aWidth, aHeight)); return NS_OK; }
nsIntRect imgFrame::GetRect() const { return nsIntRect(mOffset, mSize); }
NS_IMETHODIMP nsScriptableRegion::UnionRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) { mRegion.Or(mRegion, nsIntRect(aX, aY, aWidth, aHeight)); return NS_OK; }
PRBool imgFrame::ImageComplete() const { return mDecoded.IsEqualInterior(nsIntRect(mOffset, mSize)); }
gfxContext* gfxAlphaBoxBlur::Init(const gfxRect& aRect, const gfxIntSize& aSpreadRadius, const gfxIntSize& aBlurRadius, const gfxRect* aDirtyRect, const gfxRect* aSkipRect) { mSpreadRadius = aSpreadRadius; mBlurRadius = aBlurRadius; gfxRect rect(aRect); rect.Inflate(aBlurRadius + aSpreadRadius); rect.RoundOut(); if (aDirtyRect) { // If we get passed a dirty rect from layout, we can minimize the // shadow size and make painting faster. mHasDirtyRect = PR_TRUE; mDirtyRect = *aDirtyRect; gfxRect requiredBlurArea = mDirtyRect.Intersect(rect); requiredBlurArea.Inflate(aBlurRadius + aSpreadRadius); rect = requiredBlurArea.Intersect(rect); } else { mHasDirtyRect = PR_FALSE; } // Check rect empty after accounting for aDirtyRect, since that may have // make the rectangle empty. BoxBlurVertical and BoxBlurHorizontal require // that we have a nonzero number of rows and columns. if (rect.IsEmpty()) return nsnull; if (aSkipRect) { // If we get passed a skip rect, we can lower the amount of // blurring/spreading we need to do. We convert it to nsIntRect to avoid // expensive int<->float conversions if we were to use gfxRect instead. gfxRect skipRect = *aSkipRect; skipRect.RoundIn(); skipRect.Deflate(aBlurRadius + aSpreadRadius); gfxUtils::GfxRectToIntRect(skipRect, &mSkipRect); nsIntRect shadowIntRect; gfxUtils::GfxRectToIntRect(rect, &shadowIntRect); mSkipRect.IntersectRect(mSkipRect, shadowIntRect); if (mSkipRect.IsEqualInterior(shadowIntRect)) return nsnull; mSkipRect -= shadowIntRect.TopLeft(); } else { mSkipRect = nsIntRect(0, 0, 0, 0); } // Make an alpha-only surface to draw on. We will play with the data after // everything is drawn to create a blur effect. mImageSurface = new gfxImageSurface(gfxIntSize(static_cast<PRInt32>(rect.Width()), static_cast<PRInt32>(rect.Height())), gfxASurface::ImageFormatA8); if (!mImageSurface || mImageSurface->CairoStatus()) return nsnull; // Use a device offset so callers don't need to worry about translating // coordinates, they can draw as if this was part of the destination context // at the coordinates of rect. mImageSurface->SetDeviceOffset(-rect.TopLeft()); mContext = new gfxContext(mImageSurface); return mContext; }
nsIntRect DataTextureSourceD3D11::GetTileRect() { IntRect rect = GetTileRect(mCurrentTile); return nsIntRect(rect.x, rect.y, rect.width, rect.height); }