Bug 1286663 - Add request thumbnail native method to ThumbnailHelper; r=snorp
Add and use a request thumbnail native method call in ThumbnailHelper, instead of using the THUMBNAIL event in GeckoEvent.
This commit is contained in:
@@ -154,10 +154,12 @@ public final class ThumbnailHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log.d(LOGTAG, "Sending thumbnail event: " + mWidth + ", " + mHeight);
|
Log.d(LOGTAG, "Sending thumbnail event: " + mWidth + ", " + mHeight);
|
||||||
GeckoEvent e = GeckoEvent.createThumbnailEvent(tab.getId(), mWidth, mHeight, mBuffer);
|
requestThumbnail(mBuffer, tab.getId(), mWidth, mHeight);
|
||||||
GeckoAppShell.sendEventToGecko(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WrapForJNI
|
||||||
|
private static native void requestThumbnail(ByteBuffer data, int tabId, int width, int height);
|
||||||
|
|
||||||
/* This method is invoked by JNI once the thumbnail data is ready. */
|
/* This method is invoked by JNI once the thumbnail data is ready. */
|
||||||
@WrapForJNI(stubName = "SendThumbnail")
|
@WrapForJNI(stubName = "SendThumbnail")
|
||||||
public static void notifyThumbnail(ByteBuffer data, int tabId, boolean success, boolean shouldStore) {
|
public static void notifyThumbnail(ByteBuffer data, int tabId, boolean success, boolean shouldStore) {
|
||||||
|
|||||||
@@ -1706,7 +1706,7 @@ NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp
|
|||||||
{
|
{
|
||||||
nsAppShell* const appShell = nsAppShell::Get();
|
nsAppShell* const appShell = nsAppShell::Get();
|
||||||
if (appShell)
|
if (appShell)
|
||||||
appShell->GetBrowserApp(aBrowserApp);
|
NS_IF_ADDREF(*aBrowserApp = appShell->GetBrowserApp());
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
253
widget/android/ThumbnailHelper.h
Normal file
253
widget/android/ThumbnailHelper.h
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef ThumbnailHelper_h
|
||||||
|
#define ThumbnailHelper_h
|
||||||
|
|
||||||
|
#include "AndroidBridge.h"
|
||||||
|
#include "GeneratedJNINatives.h"
|
||||||
|
#include "gfxPlatform.h"
|
||||||
|
#include "mozIDOMWindow.h"
|
||||||
|
#include "nsAppShell.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsIChannel.h"
|
||||||
|
#include "nsIDOMWindowUtils.h"
|
||||||
|
#include "nsIDOMClientRect.h"
|
||||||
|
#include "nsIDocShell.h"
|
||||||
|
#include "nsIHttpChannel.h"
|
||||||
|
#include "nsIPresShell.h"
|
||||||
|
#include "nsIURI.h"
|
||||||
|
#include "nsPIDOMWindow.h"
|
||||||
|
#include "nsPresContext.h"
|
||||||
|
|
||||||
|
#include "mozilla/Preferences.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
class ThumbnailHelper final
|
||||||
|
: public widget::ThumbnailHelper::Natives<ThumbnailHelper>
|
||||||
|
, public jni::UsesNativeCallProxy
|
||||||
|
{
|
||||||
|
ThumbnailHelper() = delete;
|
||||||
|
|
||||||
|
// Decides if we should store thumbnails for a given docshell based on the
|
||||||
|
// presence of a Cache-Control: no-store header and the
|
||||||
|
// "browser.cache.disk_cache_ssl" pref.
|
||||||
|
static bool
|
||||||
|
ShouldStoreThumbnail(nsIDocShell* docShell)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIChannel> channel;
|
||||||
|
if (NS_FAILED(docShell->GetCurrentDocumentChannel(
|
||||||
|
getter_AddRefs(channel))) || !channel) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||||
|
if (!httpChannel) {
|
||||||
|
// Allow storing non-HTTP thumbnails.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't store thumbnails for sites that didn't load or have
|
||||||
|
// Cache-Control: no-store.
|
||||||
|
uint32_t responseStatus = 0;
|
||||||
|
bool isNoStoreResponse = false;
|
||||||
|
|
||||||
|
if (NS_FAILED(httpChannel->GetResponseStatus(&responseStatus)) ||
|
||||||
|
(responseStatus / 100) != 2 ||
|
||||||
|
NS_FAILED(httpChannel->IsNoStoreResponse(&isNoStoreResponse)) ||
|
||||||
|
isNoStoreResponse) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deny storage if we're viewing a HTTPS page with a 'Cache-Control'
|
||||||
|
// header having a value that is not 'public', unless enabled by user.
|
||||||
|
nsCOMPtr<nsIURI> uri;
|
||||||
|
bool isHttps = false;
|
||||||
|
|
||||||
|
if (NS_FAILED(channel->GetURI(getter_AddRefs(uri))) ||
|
||||||
|
!uri ||
|
||||||
|
NS_FAILED(uri->SchemeIs("https", &isHttps))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isHttps ||
|
||||||
|
Preferences::GetBool("browser.cache.disk_cache_ssl", false)) {
|
||||||
|
// Allow storing non-HTTPS thumbnails, and HTTPS ones if enabled by
|
||||||
|
// user.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoCString cacheControl;
|
||||||
|
if (NS_FAILED(httpChannel->GetResponseHeader(
|
||||||
|
NS_LITERAL_CSTRING("Cache-Control"), cacheControl))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cacheControl.IsEmpty() ||
|
||||||
|
cacheControl.LowerCaseEqualsLiteral("public")) {
|
||||||
|
// Allow no cache-control, or public cache-control.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a non-null nsIDocShell to indicate success.
|
||||||
|
static already_AddRefed<nsIDocShell>
|
||||||
|
GetThumbnailAndDocShell(mozIDOMWindowProxy* window,
|
||||||
|
jni::ByteBuffer::Param aData,
|
||||||
|
int32_t aThumbWidth, int32_t aThumbHeight)
|
||||||
|
{
|
||||||
|
// take a screenshot, as wide as possible, proportional to the destination size
|
||||||
|
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
||||||
|
nsCOMPtr<nsIDOMClientRect> rect;
|
||||||
|
float pageLeft = 0.0f, pageTop = 0.0f, pageWidth = 0.0f, pageHeight = 0.0f;
|
||||||
|
|
||||||
|
if (!utils ||
|
||||||
|
NS_FAILED(utils->GetRootBounds(getter_AddRefs(rect))) ||
|
||||||
|
!rect ||
|
||||||
|
NS_FAILED(rect->GetLeft(&pageLeft)) ||
|
||||||
|
NS_FAILED(rect->GetTop(&pageTop)) ||
|
||||||
|
NS_FAILED(rect->GetWidth(&pageWidth)) ||
|
||||||
|
NS_FAILED(rect->GetHeight(&pageHeight)) ||
|
||||||
|
int32_t(pageWidth) == 0 || int32_t(pageHeight) == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float aspectRatio = float(aThumbWidth) / float(aThumbHeight);
|
||||||
|
if (pageWidth / aspectRatio < pageHeight) {
|
||||||
|
pageHeight = pageWidth / aspectRatio;
|
||||||
|
} else {
|
||||||
|
pageWidth = pageHeight * aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsPIDOMWindowOuter> win = nsPIDOMWindowOuter::From(window);
|
||||||
|
nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
|
||||||
|
RefPtr<nsPresContext> presContext;
|
||||||
|
|
||||||
|
if (!docShell || NS_FAILED(docShell->GetPresContext(
|
||||||
|
getter_AddRefs(presContext))) || !presContext) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(gfxPlatform::GetPlatform()->
|
||||||
|
SupportsAzureContentForType(BackendType::CAIRO),
|
||||||
|
"Need BackendType::CAIRO support");
|
||||||
|
|
||||||
|
uint8_t* const data = static_cast<uint8_t*>(aData->Address());
|
||||||
|
if (!data) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool is24bit = !AndroidBridge::Bridge() ||
|
||||||
|
AndroidBridge::Bridge()->GetScreenDepth() == 24;
|
||||||
|
const uint32_t stride = aThumbWidth * (is24bit ? 4 : 2);
|
||||||
|
|
||||||
|
RefPtr<DrawTarget> dt = gfx::Factory::CreateDrawTargetForData(
|
||||||
|
BackendType::CAIRO,
|
||||||
|
data,
|
||||||
|
IntSize(aThumbWidth, aThumbHeight),
|
||||||
|
stride,
|
||||||
|
is24bit ? SurfaceFormat::B8G8R8X8
|
||||||
|
: SurfaceFormat::R5G6B5_UINT16);
|
||||||
|
|
||||||
|
if (!dt || !dt->IsValid()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
|
||||||
|
RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
|
||||||
|
MOZ_ASSERT(context); // checked the draw target above
|
||||||
|
|
||||||
|
const float scale = 1.0f;
|
||||||
|
|
||||||
|
context->SetMatrix(context->CurrentMatrix().Scale(
|
||||||
|
scale * float(aThumbWidth) / pageWidth,
|
||||||
|
scale * float(aThumbHeight) / pageHeight));
|
||||||
|
|
||||||
|
const nsRect drawRect(
|
||||||
|
nsPresContext::CSSPixelsToAppUnits(pageLeft / scale),
|
||||||
|
nsPresContext::CSSPixelsToAppUnits(pageTop / scale),
|
||||||
|
nsPresContext::CSSPixelsToAppUnits(pageWidth / scale),
|
||||||
|
nsPresContext::CSSPixelsToAppUnits(pageHeight / scale));
|
||||||
|
const uint32_t renderDocFlags =
|
||||||
|
nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
|
||||||
|
nsIPresShell::RENDER_DOCUMENT_RELATIVE;
|
||||||
|
const nscolor bgColor = NS_RGB(255, 255, 255);
|
||||||
|
|
||||||
|
if (NS_FAILED(presShell->RenderDocument(
|
||||||
|
drawRect, renderDocFlags, bgColor, context))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is24bit) {
|
||||||
|
gfxUtils::ConvertBGRAtoRGBA(data, stride * aThumbHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return docShell.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class Functor>
|
||||||
|
static void OnNativeCall(Functor&& aCall)
|
||||||
|
{
|
||||||
|
class IdleEvent : public nsAppShell::LambdaEvent<Functor>
|
||||||
|
{
|
||||||
|
using Base = nsAppShell::LambdaEvent<Functor>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IdleEvent(Functor&& aCall)
|
||||||
|
: Base(Forward<Functor>(aCall))
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Run() override
|
||||||
|
{
|
||||||
|
MessageLoop::current()->PostIdleTask(
|
||||||
|
NS_NewRunnableFunction(Move(Base::lambda)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invoke RequestThumbnail on the main thread when the thread is idle.
|
||||||
|
nsAppShell::PostEvent(MakeUnique<IdleEvent>(Forward<Functor>(aCall)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RequestThumbnail(jni::ByteBuffer::Param aData, int32_t aTabId,
|
||||||
|
int32_t aWidth, int32_t aHeight)
|
||||||
|
{
|
||||||
|
nsAppShell* const appShell = nsAppShell::Get();
|
||||||
|
if (!appShell || !aData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIAndroidBrowserApp> browserApp = appShell->GetBrowserApp();
|
||||||
|
if (!browserApp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<mozIDOMWindowProxy> window;
|
||||||
|
nsCOMPtr<nsIBrowserTab> tab;
|
||||||
|
|
||||||
|
if (NS_FAILED(browserApp->GetBrowserTab(aTabId, getter_AddRefs(tab))) ||
|
||||||
|
!tab ||
|
||||||
|
NS_FAILED(tab->GetWindow(getter_AddRefs(window))) ||
|
||||||
|
!window) {
|
||||||
|
widget::ThumbnailHelper::SendThumbnail(
|
||||||
|
aData, aTabId, /* success */ false, /* store */ false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDocShell> docShell = GetThumbnailAndDocShell(
|
||||||
|
window, aData, aWidth, aHeight);
|
||||||
|
const bool success = !!docShell;
|
||||||
|
const bool store = success ? ShouldStoreThumbnail(docShell) : false;
|
||||||
|
|
||||||
|
widget::ThumbnailHelper::SendThumbnail(aData, aTabId, success, store);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // ThumbnailHelper_h
|
||||||
@@ -62,6 +62,7 @@
|
|||||||
#include "GeckoNetworkManager.h"
|
#include "GeckoNetworkManager.h"
|
||||||
#include "GeckoScreenOrientation.h"
|
#include "GeckoScreenOrientation.h"
|
||||||
#include "PrefsHelper.h"
|
#include "PrefsHelper.h"
|
||||||
|
#include "ThumbnailHelper.h"
|
||||||
|
|
||||||
#ifdef DEBUG_ANDROID_EVENTS
|
#ifdef DEBUG_ANDROID_EVENTS
|
||||||
#define EVLOG(args...) ALOG(args)
|
#define EVLOG(args...) ALOG(args)
|
||||||
@@ -388,6 +389,7 @@ nsAppShell::nsAppShell()
|
|||||||
mozilla::GeckoNetworkManager::Init();
|
mozilla::GeckoNetworkManager::Init();
|
||||||
mozilla::GeckoScreenOrientation::Init();
|
mozilla::GeckoScreenOrientation::Init();
|
||||||
mozilla::PrefsHelper::Init();
|
mozilla::PrefsHelper::Init();
|
||||||
|
mozilla::ThumbnailHelper::Init();
|
||||||
nsWindow::InitNatives();
|
nsWindow::InitNatives();
|
||||||
|
|
||||||
widget::GeckoThread::SetState(widget::GeckoThread::State::JNI_READY());
|
widget::GeckoThread::SetState(widget::GeckoThread::State::JNI_READY());
|
||||||
|
|||||||
@@ -145,8 +145,8 @@ public:
|
|||||||
mBrowserApp = aBrowserApp;
|
mBrowserApp = aBrowserApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetBrowserApp(nsIAndroidBrowserApp* *aBrowserApp) {
|
nsIAndroidBrowserApp* GetBrowserApp() {
|
||||||
*aBrowserApp = mBrowserApp;
|
return mBrowserApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Reference in New Issue
Block a user