mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-03 20:49:27 +00:00
Bug 1096804 - Update taskbar thumbnail and preview handler code to support an asynchronous response that receives a canvas from front end js. Deprecate old sync apis. r=roc
This commit is contained in:
parent
44daa19658
commit
9e48f3f866
@ -23,12 +23,9 @@
|
||||
#include "WinUtils.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
|
||||
#include <nsIBaseWindow.h>
|
||||
#include <nsICanvasRenderingContextInternal.h>
|
||||
#include "mozilla/dom/CanvasRenderingContext2D.h"
|
||||
#include <imgIContainer.h>
|
||||
#include <nsIDocShell.h>
|
||||
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
// Defined in dwmapi in a header that needs a higher numbered _WINNT #define
|
||||
@ -37,53 +34,8 @@
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
namespace {
|
||||
|
||||
// Shared by all TaskbarPreviews to avoid the expensive creation process.
|
||||
// Manually refcounted (see gInstCount) by the ctor and dtor of TaskbarPreview.
|
||||
// This is done because static constructors aren't allowed for perf reasons.
|
||||
dom::CanvasRenderingContext2D* gCtx = nullptr;
|
||||
// Used in tracking the number of previews. Used in freeing
|
||||
// the static 2d rendering context on shutdown.
|
||||
uint32_t gInstCount = 0;
|
||||
|
||||
/* Helper method to lazily create a canvas rendering context and associate a given
|
||||
* surface with it.
|
||||
*
|
||||
* @param shell The docShell used by the canvas context for text settings and other
|
||||
* misc things.
|
||||
* @param surface The gfxSurface backing the context
|
||||
* @param width The width of the given surface
|
||||
* @param height The height of the given surface
|
||||
*/
|
||||
nsresult
|
||||
GetRenderingContext(nsIDocShell *shell, gfxASurface *surface,
|
||||
uint32_t width, uint32_t height) {
|
||||
if (!gCtx) {
|
||||
// create the canvas rendering context
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
|
||||
gCtx = new mozilla::dom::CanvasRenderingContext2D();
|
||||
NS_ADDREF(gCtx);
|
||||
}
|
||||
|
||||
// Set the surface we'll use to render.
|
||||
return gCtx->InitializeWithSurface(shell, surface, width, height);
|
||||
}
|
||||
|
||||
/* Helper method for freeing surface resources associated with the rendering context.
|
||||
*/
|
||||
void
|
||||
ResetRenderingContext() {
|
||||
if (!gCtx)
|
||||
return;
|
||||
|
||||
if (NS_FAILED(gCtx->Reset())) {
|
||||
NS_RELEASE(gCtx);
|
||||
gCtx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TaskbarPreview
|
||||
|
||||
TaskbarPreview::TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
|
||||
: mTaskbar(aTaskbar),
|
||||
@ -95,8 +47,6 @@ TaskbarPreview::TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewControl
|
||||
// TaskbarPreview may outlive the WinTaskbar that created it
|
||||
::CoInitialize(nullptr);
|
||||
|
||||
gInstCount++;
|
||||
|
||||
WindowHook &hook = GetWindowHook();
|
||||
hook.AddMonitor(WM_DESTROY, MainWindowHook, this);
|
||||
}
|
||||
@ -112,9 +62,6 @@ TaskbarPreview::~TaskbarPreview() {
|
||||
// Make sure to release before potentially uninitializing COM
|
||||
mTaskbar = nullptr;
|
||||
|
||||
if (--gInstCount == 0)
|
||||
NS_IF_RELEASE(gCtx);
|
||||
|
||||
::CoUninitialize();
|
||||
}
|
||||
|
||||
@ -357,37 +304,90 @@ TaskbarPreview::UpdateTooltip() {
|
||||
void
|
||||
TaskbarPreview::DrawBitmap(uint32_t width, uint32_t height, bool isPreview) {
|
||||
nsresult rv;
|
||||
RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(gfx::IntSize(width, height), gfx::SurfaceFormat::A8R8G8B8_UINT32);
|
||||
|
||||
nsCOMPtr<nsIDocShell> shell = do_QueryReferent(mDocShell);
|
||||
|
||||
if (!shell)
|
||||
nsCOMPtr<nsITaskbarPreviewCallback> callback =
|
||||
do_CreateInstance("@mozilla.org/widget/taskbar-preview-callback;1", &rv);
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv = GetRenderingContext(shell, surface, width, height);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
((TaskbarPreviewCallback*)callback.get())->SetPreview(this);
|
||||
|
||||
bool drawFrame = false;
|
||||
if (isPreview)
|
||||
rv = mController->DrawPreview(gCtx, &drawFrame);
|
||||
else
|
||||
rv = mController->DrawThumbnail(gCtx, width, height, &drawFrame);
|
||||
if (isPreview) {
|
||||
((TaskbarPreviewCallback*)callback.get())->SetIsPreview();
|
||||
mController->RequestPreview(callback);
|
||||
} else {
|
||||
mController->RequestThumbnail(callback, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TaskbarPreviewCallback
|
||||
|
||||
HDC hDC = surface->GetDC();
|
||||
NS_IMPL_ISUPPORTS(TaskbarPreviewCallback, nsITaskbarPreviewCallback)
|
||||
|
||||
/* void done (in nsISupports aCanvas, in boolean aDrawBorder); */
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewCallback::Done(nsISupports *aCanvas, bool aDrawBorder) {
|
||||
// We create and destroy TaskbarTabPreviews from front end code in response
|
||||
// to TabOpen and TabClose events. Each TaskbarTabPreview creates and owns a
|
||||
// proxy HWND which it hands to Windows as a tab identifier. When a tab
|
||||
// closes, TaskbarTabPreview Disable() method is called by front end, which
|
||||
// destroys the proxy window and clears mProxyWindow which is the HWND
|
||||
// returned from PreviewWindow(). So, since this is async, we should check to
|
||||
// be sure the tab is still alive before doing all this gfx work and making
|
||||
// dwm calls. To accomplish this we check the result of PreviewWindow().
|
||||
if (!aCanvas || !mPreview || !mPreview->PreviewWindow() ||
|
||||
!mPreview->IsWindowAvailable()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLCanvasElement> domcanvas(do_QueryInterface(aCanvas));
|
||||
dom::HTMLCanvasElement * canvas = ((dom::HTMLCanvasElement*)domcanvas.get());
|
||||
if (!canvas) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<gfx::SourceSurface> source = canvas->GetSurfaceSnapshot();
|
||||
if (!source) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
RefPtr<gfxWindowsSurface> target = new gfxWindowsSurface(source->GetSize(),
|
||||
gfx::SurfaceFormat::A8R8G8B8_UINT32);
|
||||
if (!target) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> srcSurface = source->GetDataSurface();
|
||||
RefPtr<gfxImageSurface> imageSurface = target->GetAsImageSurface();
|
||||
if (!srcSurface || !imageSurface) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
gfx::DataSourceSurface::MappedSurface sourceMap;
|
||||
srcSurface->Map(gfx::DataSourceSurface::READ, &sourceMap);
|
||||
mozilla::gfx::CopySurfaceDataToPackedArray(sourceMap.mData,
|
||||
imageSurface->Data(),
|
||||
srcSurface->GetSize(),
|
||||
sourceMap.mStride,
|
||||
BytesPerPixel(srcSurface->GetFormat()));
|
||||
srcSurface->Unmap();
|
||||
|
||||
HDC hDC = target->GetDC();
|
||||
HBITMAP hBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP);
|
||||
|
||||
DWORD flags = drawFrame ? DWM_SIT_DISPLAYFRAME : 0;
|
||||
DWORD flags = aDrawBorder ? DWM_SIT_DISPLAYFRAME : 0;
|
||||
POINT pptClient = { 0, 0 };
|
||||
if (isPreview)
|
||||
WinUtils::dwmSetIconicLivePreviewBitmapPtr(PreviewWindow(), hBitmap, &pptClient, flags);
|
||||
else
|
||||
WinUtils::dwmSetIconicThumbnailPtr(PreviewWindow(), hBitmap, flags);
|
||||
|
||||
ResetRenderingContext();
|
||||
HRESULT hr;
|
||||
if (!mIsThumbnail) {
|
||||
hr = WinUtils::dwmSetIconicLivePreviewBitmapPtr(mPreview->PreviewWindow(),
|
||||
hBitmap, &pptClient, flags);
|
||||
} else {
|
||||
hr = WinUtils::dwmSetIconicThumbnailPtr(mPreview->PreviewWindow(),
|
||||
hBitmap, flags);
|
||||
}
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -13,6 +13,7 @@
|
||||
#undef LogSeverity // SetupAPI.h #defines this as DWORD
|
||||
|
||||
#include <nsITaskbarPreview.h>
|
||||
#include <nsITaskbarPreviewController.h>
|
||||
#include <nsAutoPtr.h>
|
||||
#include <nsString.h>
|
||||
#include <nsWeakPtr.h>
|
||||
@ -22,11 +23,15 @@
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class TaskbarPreviewCallback;
|
||||
|
||||
class TaskbarPreview : public nsITaskbarPreview
|
||||
{
|
||||
public:
|
||||
TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
|
||||
|
||||
friend class TaskbarPreviewCallback;
|
||||
|
||||
NS_DECL_NSITASKBARPREVIEW
|
||||
|
||||
protected:
|
||||
@ -97,6 +102,37 @@ private:
|
||||
static TaskbarPreview *sActivePreview;
|
||||
};
|
||||
|
||||
/*
|
||||
* Callback object TaskbarPreview hands to preview controllers when we
|
||||
* request async thumbnail or live preview images. Controllers invoke
|
||||
* this interface once they have aquired the requested image.
|
||||
*/
|
||||
class TaskbarPreviewCallback : public nsITaskbarPreviewCallback
|
||||
{
|
||||
public:
|
||||
TaskbarPreviewCallback() :
|
||||
mIsThumbnail(true) {
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITASKBARPREVIEWCALLBACK
|
||||
|
||||
void SetPreview(TaskbarPreview* aPreview) {
|
||||
mPreview = aPreview;
|
||||
}
|
||||
|
||||
void SetIsPreview() {
|
||||
mIsThumbnail = false;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~TaskbarPreviewCallback() {}
|
||||
|
||||
private:
|
||||
RefPtr<TaskbarPreview> mPreview;
|
||||
bool mIsThumbnail;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -164,15 +164,27 @@ DefaultController::GetThumbnailAspectRatio(float *aThumbnailAspectRatio) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
NS_IMETHODIMP
|
||||
DefaultController::DrawPreview(nsISupports *ctx, bool *rDrawFrame) {
|
||||
*rDrawFrame = true;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
NS_IMETHODIMP
|
||||
DefaultController::DrawThumbnail(nsISupports *ctx, uint32_t width, uint32_t height, bool *rDrawFrame) {
|
||||
*rDrawFrame = false;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::RequestThumbnail(nsITaskbarPreviewCallback *aCallback, uint32_t width, uint32_t height) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::DrawThumbnail(nsISupports *ctx, uint32_t width, uint32_t height, bool *rDrawFrame) {
|
||||
*rDrawFrame = false;
|
||||
DefaultController::RequestPreview(nsITaskbarPreviewCallback *aCallback) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user