Merge inbound to mozilla-central. a=merge

This commit is contained in:
Noemi Erli 2018-09-14 06:31:31 +03:00
Родитель 5c593ac182 2d47fcde1c
Коммит c2716211ca
60 изменённых файлов: 848 добавлений и 963 удалений

Просмотреть файл

@ -14,6 +14,7 @@ support-files =
support-files =
browser_autoplay_blocked.html
../general/audio.ogg
skip-if = verify && os == 'linux' && debug # Bug 1483648
[browser_autoplay_doorhanger.js]
support-files =
browser_autoplay_blocked.html

Просмотреть файл

@ -6,12 +6,10 @@
const Services = require("Services");
const protocol = require("devtools/shared/protocol");
const defer = require("devtools/shared/defer");
const {LongStringActor} = require("devtools/server/actors/string");
const {DebuggerServer} = require("devtools/server/main");
const {getSystemInfo, getSetting} = require("devtools/shared/system");
const {getSystemInfo} = require("devtools/shared/system");
const {deviceSpec} = require("devtools/shared/specs/device");
const FileReader = require("FileReader");
exports.DeviceActor = protocol.ActorClassWithSpec(deviceSpec, {
_desc: null,
@ -20,23 +18,6 @@ exports.DeviceActor = protocol.ActorClassWithSpec(deviceSpec, {
return getSystemInfo();
},
getWallpaper: function() {
const deferred = defer();
getSetting("wallpaper.image").then((blob) => {
const reader = new FileReader();
const conn = this.conn;
reader.addEventListener("load", function() {
const str = new LongStringActor(conn, reader.result);
deferred.resolve(str);
});
reader.addEventListener("error", function() {
deferred.reject(reader.error);
});
reader.readAsDataURL(blob);
});
return deferred.promise;
},
screenshotToDataURL: function() {
const window = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
const { devicePixelRatio } = window;

Просмотреть файл

@ -10,7 +10,6 @@ const deviceSpec = generateActorSpec({
methods: {
getDescription: {request: {}, response: { value: RetVal("json")}},
getWallpaper: {request: {}, response: { value: RetVal("longstring")}},
screenshotToDataURL: {request: {}, response: { value: RetVal("longstring")}},
},
});

Просмотреть файл

@ -6,8 +6,6 @@
const { Cc, Ci } = require("chrome");
loader.lazyRequireGetter(this, "Services");
loader.lazyRequireGetter(this, "promise");
loader.lazyRequireGetter(this, "defer", "devtools/shared/defer");
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
loader.lazyRequireGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm", true);
@ -239,30 +237,5 @@ function getScreenDimensions() {
return 11;
}
function getSetting(name) {
const deferred = defer();
if ("@mozilla.org/settingsService;1" in Cc) {
let settingsService;
// TODO bug 1205797, make this work in child processes.
try {
settingsService = Cc["@mozilla.org/settingsService;1"]
.getService(Ci.nsISettingsService);
} catch (e) {
return promise.reject(e);
}
settingsService.createLock().get(name, {
handle: (_, value) => deferred.resolve(value),
handleError: (error) => deferred.reject(error),
});
} else {
deferred.reject(new Error("No settings service"));
}
return deferred.promise;
}
exports.getSystemInfo = getSystemInfo;
exports.getSetting = getSetting;
exports.getScreenDimensions = getScreenDimensions;

Просмотреть файл

@ -9055,33 +9055,30 @@ nsDocShell::CopyFavicon(nsIURI* aOldURI,
#endif
}
struct InternalLoadData
class InternalLoadEvent : public Runnable
{
public:
InternalLoadData(nsDocShell* aDocShell,
nsIURI* aURI,
nsIURI* aOriginalURI,
Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
bool aKeepResultPrincipalURIIfSet,
bool aLoadReplace,
nsIURI* aReferrer, uint32_t aReferrerPolicy,
nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
uint32_t aFlags,
const nsAString& aWindowTarget,
const char* aTypeHint,
const nsAString& aFileName,
nsIInputStream* aPostData,
nsIInputStream* aHeadersData,
uint32_t aLoadType,
nsISHEntry* aSHEntry,
bool aFirstParty,
const nsAString& aSrcdoc,
nsIDocShell* aSourceDocShell,
nsIURI* aBaseURI,
nsIDocShell** aDocShell2,
nsIRequest** aRequest)
: mSrcdoc(aSrcdoc)
InternalLoadEvent(nsDocShell* aDocShell,
nsIURI* aURI,
nsIURI* aOriginalURI,
Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
bool aKeepResultPrincipalURIIfSet,
bool aLoadReplace,
nsIURI* aReferrer, uint32_t aReferrerPolicy,
nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
uint32_t aFlags,
const char* aTypeHint,
nsIInputStream* aPostData,
nsIInputStream* aHeadersData,
uint32_t aLoadType,
nsISHEntry* aSHEntry,
bool aFirstParty,
const nsAString& aSrcdoc,
nsIDocShell* aSourceDocShell,
nsIURI* aBaseURI)
: mozilla::Runnable("InternalLoadEvent")
, mSrcdoc(aSrcdoc)
, mDocShell(aDocShell)
, mURI(aURI)
, mOriginalURI(aOriginalURI)
@ -9096,14 +9093,10 @@ public:
, mHeadersData(aHeadersData)
, mSHEntry(aSHEntry)
, mFlags(aFlags)
, mWindowTarget(aWindowTarget)
, mFileName(aFileName)
, mLoadType(aLoadType)
, mFirstParty(aFirstParty)
, mSourceDocShell(aSourceDocShell)
, mBaseURI(aBaseURI)
, mDocShell2(aDocShell2)
, mRequest(aRequest)
{
// Make sure to keep null things null as needed
if (aTypeHint) {
@ -9113,7 +9106,8 @@ public:
}
}
nsresult Run()
NS_IMETHOD
Run() override
{
return mDocShell->InternalLoad(mURI, mOriginalURI, mResultPrincipalURI,
mKeepResultPrincipalURIIfSet,
@ -9121,16 +9115,17 @@ public:
mReferrer,
mReferrerPolicy,
mTriggeringPrincipal, mPrincipalToInherit,
mFlags, mWindowTarget,
mFlags, EmptyString(),
mTypeHint.IsVoid() ? nullptr
: mTypeHint.get(),
mFileName, mPostData,
VoidString(), mPostData,
mHeadersData, mLoadType, mSHEntry,
mFirstParty, mSrcdoc, mSourceDocShell,
mBaseURI, mDocShell2,
mRequest);
mBaseURI, nullptr,
nullptr);
}
private:
nsCString mTypeHint;
nsString mSrcdoc;
@ -9148,174 +9143,12 @@ public:
nsCOMPtr<nsIInputStream> mHeadersData;
nsCOMPtr<nsISHEntry> mSHEntry;
uint32_t mFlags;
nsString mWindowTarget;
nsString mFileName;
uint32_t mLoadType;
bool mFirstParty;
nsCOMPtr<nsIDocShell> mSourceDocShell;
nsCOMPtr<nsIURI> mBaseURI;
nsIDocShell** mDocShell2;
nsIRequest** mRequest;
};
class InternalLoadEvent : public Runnable
{
public:
InternalLoadEvent(nsDocShell* aDocShell,
nsIURI* aURI,
nsIURI* aOriginalURI,
Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
bool aKeepResultPrincipalURIIfSet,
bool aLoadReplace,
nsIURI* aReferrer,
uint32_t aReferrerPolicy,
nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
uint32_t aFlags,
const char* aTypeHint,
nsIInputStream* aPostData,
nsIInputStream* aHeadersData,
uint32_t aLoadType,
nsISHEntry* aSHEntry,
bool aFirstParty,
const nsAString& aSrcdoc,
nsIDocShell* aSourceDocShell,
nsIURI* aBaseURI)
: mozilla::Runnable("InternalLoadEvent")
, mLoadData(aDocShell,
aURI,
aOriginalURI,
aResultPrincipalURI,
aKeepResultPrincipalURIIfSet,
aLoadReplace,
aReferrer,
aReferrerPolicy,
aTriggeringPrincipal,
aPrincipalToInherit,
aFlags,
EmptyString(),
aTypeHint,
VoidString(),
aPostData,
aHeadersData,
aLoadType,
aSHEntry,
aFirstParty,
aSrcdoc,
aSourceDocShell,
aBaseURI,
nullptr,
nullptr)
{}
NS_IMETHOD
Run() override
{
return mLoadData.Run();
}
private:
InternalLoadData mLoadData;
};
class LoadURIDelegateHandler final : public PromiseNativeHandler
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(LoadURIDelegateHandler)
LoadURIDelegateHandler(nsDocShell* aDocShell,
nsIURI* aURI,
nsIURI* aOriginalURI,
Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
bool aKeepResultPrincipalURIIfSet,
bool aLoadReplace,
nsIURI* aReferrer,
uint32_t aReferrerPolicy,
nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
uint32_t aFlags,
const nsAString& aWindowTarget,
const char* aTypeHint,
const nsAString& aFileName,
nsIInputStream* aPostData,
nsIInputStream* aHeadersData,
uint32_t aLoadType,
nsISHEntry* aSHEntry,
bool aFirstParty,
const nsAString& aSrcdoc,
nsIDocShell* aSourceDocShell,
nsIURI* aBaseURI,
nsIDocShell** aDocShell2,
nsIRequest** aRequest)
: mLoadData(aDocShell,
aURI,
aOriginalURI,
aResultPrincipalURI,
aKeepResultPrincipalURIIfSet,
aLoadReplace,
aReferrer,
aReferrerPolicy,
aTriggeringPrincipal,
aPrincipalToInherit,
aFlags,
aWindowTarget,
aTypeHint,
aFileName,
aPostData,
aHeadersData,
aLoadType,
aSHEntry,
aFirstParty,
aSrcdoc,
aSourceDocShell,
aBaseURI,
aDocShell2,
aRequest)
{}
void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
if (aValue.isBoolean() && !aValue.toBoolean()) {
// Things went fine, not handled by app, let Gecko do its thing
mLoadData.Run();
} else if (!aValue.isBoolean()) {
// If the promise resolves to a non-boolean, let Gecko handle the load
mLoadData.Run();
}
}
void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
// In the event of a rejected callback, let Gecko handle the load
mLoadData.Run();
}
private:
~LoadURIDelegateHandler()
{}
InternalLoadData mLoadData;
};
NS_IMPL_CYCLE_COLLECTION(LoadURIDelegateHandler, mLoadData.mDocShell,
mLoadData.mURI, mLoadData.mOriginalURI,
mLoadData.mResultPrincipalURI, mLoadData.mReferrer,
mLoadData.mTriggeringPrincipal,
mLoadData.mPrincipalToInherit,
mLoadData.mPostData, mLoadData.mHeadersData,
mLoadData.mSHEntry, mLoadData.mSourceDocShell,
mLoadData.mBaseURI)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LoadURIDelegateHandler)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(LoadURIDelegateHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadURIDelegateHandler)
/**
* Returns true if we started an asynchronous load (i.e., from the network), but
* the document we're loading there hasn't yet become this docshell's active
@ -9563,10 +9396,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
const bool isDocumentAuxSandboxed = doc &&
(doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
const bool checkLoadDelegates = !(aFlags & INTERNAL_LOAD_FLAGS_DELEGATES_CHECKED);
aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_DELEGATES_CHECKED;
if (aURI && mLoadURIDelegate && checkLoadDelegates && aLoadType != LOAD_ERROR_PAGE &&
if (aURI && mLoadURIDelegate && aLoadType != LOAD_ERROR_PAGE &&
(!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
// Dispatch only load requests for the current or a new window to the
// delegate, e.g., to allow for GeckoView apps to handle the load event
@ -9579,24 +9409,11 @@ nsDocShell::InternalLoad(nsIURI* aURI,
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
RefPtr<dom::Promise> promise;
bool loadURIHandled = false;
rv = mLoadURIDelegate->LoadURI(aURI, where, aFlags, aTriggeringPrincipal,
getter_AddRefs(promise));
if (NS_SUCCEEDED(rv) && promise) {
const uint32_t flags = aFlags | INTERNAL_LOAD_FLAGS_DELEGATES_CHECKED;
RefPtr<LoadURIDelegateHandler> handler =
new LoadURIDelegateHandler(this, aURI, aOriginalURI, aResultPrincipalURI,
aKeepResultPrincipalURIIfSet,
aLoadReplace, aReferrer, aReferrerPolicy,
aTriggeringPrincipal, aPrincipalToInherit,
flags, aWindowTarget, aTypeHint, aFileName, aPostData,
aHeadersData, aLoadType, aSHEntry, aFirstParty,
aSrcdoc, aSourceDocShell, aBaseURI, nullptr, nullptr);
promise->AppendNativeHandler(handler);
// Checking for load delegates; InternalLoad will be re-called if needed.
&loadURIHandled);
if (NS_SUCCEEDED(rv) && loadURIHandled) {
// The request has been handled, nothing to do here.
return NS_OK;
}
}

Просмотреть файл

@ -119,9 +119,6 @@ interface nsIDocShell : nsIDocShellTreeItem
// Whether a top-level data URI navigation is allowed for that load
const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI = 0x200;
// Whether load delegates have already been checked for this load
const long INTERNAL_LOAD_FLAGS_DELEGATES_CHECKED = 0x400;
// Whether the load was triggered by user interaction.
const long INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED = 0x1000;

Просмотреть файл

@ -64,6 +64,7 @@ nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
, mIsSrcdocEntry(aOther.mIsSrcdocEntry)
, mScrollRestorationIsManual(false)
, mLoadedInThisProcess(aOther.mLoadedInThisProcess)
, mPersist(aOther.mPersist)
{
}

Просмотреть файл

@ -1,15 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
with Files("**"):
BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
XPIDL_SOURCES += [
'nsISettingsService.idl',
]
XPIDL_MODULE = 'dom_settings'

Просмотреть файл

@ -1,37 +0,0 @@
/* 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/. */
#include "domstubs.idl"
[scriptable, uuid(aad47850-2e87-11e2-81c1-0800200c9a66)]
interface nsISettingsServiceCallback : nsISupports
{
void handle(in DOMString aName, in jsval aResult);
void handleError(in DOMString aErrorMessage);
};
[scriptable, uuid(f1b3d820-8e75-11e3-baa8-0800200c9a66)]
interface nsISettingsTransactionCompleteCallback : nsISupports
{
void handle();
void handleAbort(in DOMString aErrorMessage);
};
[scriptable, uuid(d7a395a0-e292-11e1-834e-1761d57f5f99)]
interface nsISettingsServiceLock : nsISupports
{
void set(in string aName,
in jsval aValue,
in nsISettingsServiceCallback aCallback,
[optional] in string aMessage);
void get(in string aName, in nsISettingsServiceCallback aCallback);
};
[scriptable, uuid(d1ed155c-9f90-47bb-91c2-7eac54d69f4b)]
interface nsISettingsService : nsISupports
{
nsISettingsServiceLock createLock([optional] in nsISettingsTransactionCompleteCallback aCallback);
void receiveMessage(in jsval aMessage);
};

Просмотреть файл

@ -24,7 +24,7 @@ use prim_store::{BorderSource, Primitive, PrimitiveDetails};
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree};
use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
use renderer::BLOCKS_PER_UV_RECT;
use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache};
use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache, ImageProperties};
use scene::FilterOpHelpers;
use std::{f32, i32};
use tiling::{RenderTargetContext};
@ -1604,6 +1604,30 @@ impl Primitive {
}
}
}
pub fn is_cacheable(
&self,
resource_cache: &ResourceCache
) -> bool {
let image_key = match self.details {
PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Image{ request, .. }, .. }) => {
request.key
}
PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::YuvImage{ yuv_key, .. }, .. }) => {
yuv_key[0]
}
PrimitiveDetails::Brush(_) |
PrimitiveDetails::TextRun(..) => {
return true
}
};
match resource_cache.get_image_properties(image_key) {
Some(ImageProperties { external_image: Some(_), .. }) => {
false
}
_ => true
}
}
}
impl PictureSurface {

Просмотреть файл

@ -4,7 +4,7 @@
use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF};
use api::{ColorU, DeviceRect, DeviceSize, LayoutSizeAu, LayoutPrimitiveInfo, LayoutToDeviceScale};
use api::{DevicePixel, DeviceVector2D, DevicePoint, DeviceIntSize, LayoutRect, LayoutSize, NormalBorder};
use api::{DeviceVector2D, DevicePoint, DeviceIntSize, LayoutRect, LayoutSize, NormalBorder};
use app_units::Au;
use ellipse::Ellipse;
use display_list_flattener::DisplayListFlattener;
@ -24,7 +24,7 @@ pub const MAX_BORDER_RESOLUTION: u32 = 2048;
/// Maximum number of dots or dashes per segment to avoid freezing and filling up
/// memory with unreasonable inputs. It would be better to address this by not building
/// a list of per-dot information in the first place.
pub const MAX_DASH_COUNT: usize = 2048;
pub const MAX_DASH_COUNT: u32 = 2048;
trait AuSizeConverter {
fn to_au(&self) -> LayoutSizeAu;
@ -241,283 +241,271 @@ pub enum BorderClipKind {
Dot = 3,
}
/// The source data for a border corner clip mask.
#[derive(Debug, Clone)]
struct BorderCornerClipSource {
// FIXME(emilio): the `max_clip_count` name makes no sense for dashed
// borders now that it represents half-dashes.
max_clip_count: usize,
kind: BorderClipKind,
widths: DeviceSize,
fn compute_outer_and_clip_sign(
corner_segment: BorderSegment,
radius: DeviceSize,
ellipse: Ellipse<DevicePixel>,
) -> (DevicePoint, DeviceVector2D) {
let outer_scale = match corner_segment {
BorderSegment::TopLeft => DeviceVector2D::new(0.0, 0.0),
BorderSegment::TopRight => DeviceVector2D::new(1.0, 0.0),
BorderSegment::BottomRight => DeviceVector2D::new(1.0, 1.0),
BorderSegment::BottomLeft => DeviceVector2D::new(0.0, 1.0),
_ => panic!("bug: expected a corner segment"),
};
let outer = DevicePoint::new(
outer_scale.x * radius.width,
outer_scale.y * radius.height,
);
let clip_sign = DeviceVector2D::new(
1.0 - 2.0 * outer_scale.x,
1.0 - 2.0 * outer_scale.y,
);
(outer, clip_sign)
}
impl BorderCornerClipSource {
pub fn new(
corner_radius: DeviceSize,
widths: DeviceSize,
kind: BorderClipKind,
) -> BorderCornerClipSource {
// Work out a dash length (and therefore dash count)
// based on the width of the border edges. The "correct"
// dash length is not mentioned in the CSS borders
// spec. The calculation below is similar, but not exactly
// the same as what Gecko uses.
// TODO(gw): Iterate on this to get it closer to what Gecko
// uses for dash length.
fn write_dashed_corner_instances(
corner_radius: DeviceSize,
widths: DeviceSize,
segment: BorderSegment,
base_instance: &BorderInstance,
instances: &mut Vec<BorderInstance>,
) -> Result<(), ()> {
let ellipse = Ellipse::new(corner_radius);
let (ellipse, max_clip_count) = match kind {
BorderClipKind::DashEdge => unreachable!("not for corners"),
BorderClipKind::DashCorner => {
let ellipse = Ellipse::new(corner_radius);
let average_border_width = 0.5 * (widths.width + widths.height);
let average_border_width = 0.5 * (widths.width + widths.height);
let (_half_dash, num_half_dashes) =
compute_half_dash(average_border_width, ellipse.total_arc_length);
let (_half_dash, num_half_dashes) =
compute_half_dash(average_border_width, ellipse.total_arc_length);
if num_half_dashes == 0 {
return Err(());
}
// Round that up to the nearest integer, so that the dash length
// doesn't exceed the ratio above. Add one extra dash to cover
// the last half-dash of the arc.
(ellipse, num_half_dashes as usize)
}
BorderClipKind::Dot => {
let mut corner_radius = corner_radius;
if corner_radius.width < (widths.width / 2.0) {
corner_radius.width = 0.0;
}
if corner_radius.height < (widths.height / 2.0) {
corner_radius.height = 0.0;
}
let num_half_dashes = num_half_dashes.min(MAX_DASH_COUNT);
if corner_radius.width == 0. && corner_radius.height == 0. {
(Ellipse::new(corner_radius), 1)
} else {
// The centers of dots follow an ellipse along the middle of the
// border radius.
let inner_radius = (corner_radius - widths * 0.5).abs();
let ellipse = Ellipse::new(inner_radius);
let (outer, clip_sign) = compute_outer_and_clip_sign(segment, corner_radius);
// Allocate a "worst case" number of dot clips. This can be
// calculated by taking the minimum edge radius, since that
// will result in the maximum number of dots along the path.
let min_diameter = widths.width.min(widths.height);
let instance_count = num_half_dashes / 4 + 1;
instances.reserve(instance_count as usize);
// Get the number of circles (assuming spacing of one diameter
// between dots).
let max_dot_count = 0.5 * ellipse.total_arc_length / min_diameter;
let half_dash_arc_length =
ellipse.total_arc_length / num_half_dashes as f32;
let dash_length = 2. * half_dash_arc_length;
// Add space for one extra dot since they are centered at the
// start of the arc.
(ellipse, max_dot_count.ceil() as usize)
}
}
let mut current_length = 0.;
for i in 0..instance_count {
let arc_length0 = current_length;
current_length += if i == 0 {
half_dash_arc_length
} else {
dash_length
};
BorderCornerClipSource {
kind,
max_clip_count,
ellipse,
widths,
radius: corner_radius,
let arc_length1 = current_length;
current_length += dash_length;
let alpha = ellipse.find_angle_for_arc_length(arc_length0);
let beta = ellipse.find_angle_for_arc_length(arc_length1);
let (point0, tangent0) = ellipse.get_point_and_tangent(alpha);
let (point1, tangent1) = ellipse.get_point_and_tangent(beta);
let point0 = DevicePoint::new(
outer.x + clip_sign.x * (corner_radius.width - point0.x),
outer.y + clip_sign.y * (corner_radius.height - point0.y),
);
let tangent0 = DeviceVector2D::new(
-tangent0.x * clip_sign.x,
-tangent0.y * clip_sign.y,
);
let point1 = DevicePoint::new(
outer.x + clip_sign.x * (corner_radius.width - point1.x),
outer.y + clip_sign.y * (corner_radius.height - point1.y),
);
let tangent1 = DeviceVector2D::new(
-tangent1.x * clip_sign.x,
-tangent1.y * clip_sign.y,
);
instances.push(BorderInstance {
flags: base_instance.flags | ((BorderClipKind::DashCorner as i32) << 24),
clip_params: [
point0.x,
point0.y,
tangent0.x,
tangent0.y,
point1.x,
point1.y,
tangent1.x,
tangent1.y,
],
.. *base_instance
});
}
Ok(())
}
fn write_dotted_corner_instances(
corner_radius: DeviceSize,
widths: DeviceSize,
segment: BorderSegment,
base_instance: &BorderInstance,
instances: &mut Vec<BorderInstance>,
) -> Result<(), ()> {
let mut corner_radius = corner_radius;
if corner_radius.width < (widths.width / 2.0) {
corner_radius.width = 0.0;
}
if corner_radius.height < (widths.height / 2.0) {
corner_radius.height = 0.0;
}
let (ellipse, max_dot_count) =
if corner_radius.width == 0. && corner_radius.height == 0. {
(Ellipse::new(corner_radius), 1)
} else {
// The centers of dots follow an ellipse along the middle of the
// border radius.
let inner_radius = (corner_radius - widths * 0.5).abs();
let ellipse = Ellipse::new(inner_radius);
// Allocate a "worst case" number of dot clips. This can be
// calculated by taking the minimum edge radius, since that
// will result in the maximum number of dots along the path.
let min_diameter = widths.width.min(widths.height);
// Get the number of circles (assuming spacing of one diameter
// between dots).
let max_dot_count = 0.5 * ellipse.total_arc_length / min_diameter;
// Add space for one extra dot since they are centered at the
// start of the arc.
(ellipse, max_dot_count.ceil() as usize)
};
if max_dot_count == 0 {
return Err(());
}
if max_dot_count == 1 {
let dot_diameter = lerp(widths.width, widths.height, 0.5);
instances.push(BorderInstance {
flags: base_instance.flags | ((BorderClipKind::Dot as i32) << 24),
clip_params: [
widths.width / 2.0, widths.height / 2.0, 0.5 * dot_diameter, 0.,
0., 0., 0., 0.,
],
.. *base_instance
});
return Ok(());
}
let max_dot_count = max_dot_count.min(MAX_DASH_COUNT as usize);
// FIXME(emilio): Should probably use SmallVec.
let mut forward_dots = Vec::with_capacity(max_dot_count / 2 + 1);
let mut back_dots = Vec::with_capacity(max_dot_count / 2 + 1);
let mut leftover_arc_length = 0.0;
// Alternate between adding dots at the start and end of the
// ellipse arc. This ensures that we always end up with an exact
// half dot at each end of the arc, to match up with the edges.
forward_dots.push(DotInfo::new(widths.width, widths.width));
back_dots.push(DotInfo::new(
ellipse.total_arc_length - widths.height,
widths.height,
));
let (outer, clip_sign) = compute_outer_and_clip_sign(segment, corner_radius);
for dot_index in 0 .. max_dot_count {
let prev_forward_pos = *forward_dots.last().unwrap();
let prev_back_pos = *back_dots.last().unwrap();
// Select which end of the arc to place a dot from.
// This just alternates between the start and end of
// the arc, which ensures that there is always an
// exact half-dot at each end of the ellipse.
let going_forward = dot_index & 1 == 0;
let (next_dot_pos, leftover) = if going_forward {
let next_dot_pos =
prev_forward_pos.arc_pos + 2.0 * prev_forward_pos.diameter;
(next_dot_pos, prev_back_pos.arc_pos - next_dot_pos)
} else {
let next_dot_pos = prev_back_pos.arc_pos - 2.0 * prev_back_pos.diameter;
(next_dot_pos, next_dot_pos - prev_forward_pos.arc_pos)
};
// Use a lerp between each edge's dot
// diameter, based on the linear distance
// along the arc to get the diameter of the
// dot at this arc position.
let t = next_dot_pos / ellipse.total_arc_length;
let dot_diameter = lerp(widths.width, widths.height, t);
// If we can't fit a dot, bail out.
if leftover < dot_diameter {
leftover_arc_length = leftover;
break;
}
// We can place a dot!
let dot = DotInfo::new(next_dot_pos, dot_diameter);
if going_forward {
forward_dots.push(dot);
} else {
back_dots.push(dot);
}
}
// TODO(gw): The naming and structure of BorderCornerClipSource
// don't really make sense. I've left it this way
// for now in order to reduce the size of the
// patch a bit. In the future, when we spent some
// time working on dot/dash placement, we should
// restructure this code to be more consistent
// with how border rendering works now.
pub fn write(self, segment: BorderSegment) -> Vec<[f32; 8]> {
let mut dot_dash_data = Vec::new();
// Now step through the dots, and distribute any extra
// leftover space on the arc between them evenly. Once
// the final arc position is determined, generate the correct
// arc positions and angles that get passed to the clip shader.
let number_of_dots = forward_dots.len() + back_dots.len();
let extra_space_per_dot = leftover_arc_length / (number_of_dots - 1) as f32;
if self.max_clip_count == 0 {
return dot_dash_data;
}
let create_dot_data = |arc_length: f32, dot_radius: f32| -> [f32; 8] {
// Represents the GPU data for drawing a single dot to a clip mask. The order
// these are specified must stay in sync with the way this data is read in the
// dot clip shader.
let theta = ellipse.find_angle_for_arc_length(arc_length);
let (center, _) = ellipse.get_point_and_tangent(theta);
let outer_scale = match segment {
BorderSegment::TopLeft => DeviceVector2D::new(0.0, 0.0),
BorderSegment::TopRight => DeviceVector2D::new(1.0, 0.0),
BorderSegment::BottomRight => DeviceVector2D::new(1.0, 1.0),
BorderSegment::BottomLeft => DeviceVector2D::new(0.0, 1.0),
_ => unreachable!(),
};
let outer = DevicePoint::new(
outer_scale.x * self.radius.width,
outer_scale.y * self.radius.height,
);
let clip_sign = DeviceVector2D::new(
1.0 - 2.0 * outer_scale.x,
1.0 - 2.0 * outer_scale.y,
let center = DevicePoint::new(
outer.x + clip_sign.x * (corner_radius.width - center.x),
outer.y + clip_sign.y * (corner_radius.height - center.y),
);
let max_clip_count = self.max_clip_count.min(MAX_DASH_COUNT);
[center.x, center.y, dot_radius, 0.0, 0.0, 0.0, 0.0, 0.0]
};
match self.kind {
BorderClipKind::DashEdge => unreachable!("not for corners"),
BorderClipKind::DashCorner => {
// Get the correct half-dash arc length.
let half_dash_arc_length =
self.ellipse.total_arc_length / max_clip_count as f32;
let dash_length = 2. * half_dash_arc_length;
let mut current_length = 0.;
dot_dash_data.reserve(max_clip_count / 4 + 1);
for i in 0 .. (max_clip_count / 4 + 1) {
let arc_length0 = current_length;
current_length += if i == 0 {
half_dash_arc_length
} else {
dash_length
};
let arc_length1 = current_length;
current_length += dash_length;
let alpha = self.ellipse.find_angle_for_arc_length(arc_length0);
let beta = self.ellipse.find_angle_for_arc_length(arc_length1);
let (point0, tangent0) = self.ellipse.get_point_and_tangent(alpha);
let (point1, tangent1) = self.ellipse.get_point_and_tangent(beta);
let point0 = DevicePoint::new(
outer.x + clip_sign.x * (self.radius.width - point0.x),
outer.y + clip_sign.y * (self.radius.height - point0.y),
);
let tangent0 = DeviceVector2D::new(
-tangent0.x * clip_sign.x,
-tangent0.y * clip_sign.y,
);
let point1 = DevicePoint::new(
outer.x + clip_sign.x * (self.radius.width - point1.x),
outer.y + clip_sign.y * (self.radius.height - point1.y),
);
let tangent1 = DeviceVector2D::new(
-tangent1.x * clip_sign.x,
-tangent1.y * clip_sign.y,
);
dot_dash_data.push([
point0.x,
point0.y,
tangent0.x,
tangent0.y,
point1.x,
point1.y,
tangent1.x,
tangent1.y,
]);
}
}
BorderClipKind::Dot if max_clip_count == 1 => {
let dot_diameter = lerp(self.widths.width, self.widths.height, 0.5);
dot_dash_data.push([
self.widths.width / 2.0, self.widths.height / 2.0, 0.5 * dot_diameter, 0.,
0., 0., 0., 0.,
]);
}
BorderClipKind::Dot => {
let mut forward_dots = Vec::with_capacity(max_clip_count / 2 + 1);
let mut back_dots = Vec::with_capacity(max_clip_count / 2 + 1);
let mut leftover_arc_length = 0.0;
// Alternate between adding dots at the start and end of the
// ellipse arc. This ensures that we always end up with an exact
// half dot at each end of the arc, to match up with the edges.
forward_dots.push(DotInfo::new(self.widths.width, self.widths.width));
back_dots.push(DotInfo::new(
self.ellipse.total_arc_length - self.widths.height,
self.widths.height,
));
for dot_index in 0 .. max_clip_count {
let prev_forward_pos = *forward_dots.last().unwrap();
let prev_back_pos = *back_dots.last().unwrap();
// Select which end of the arc to place a dot from.
// This just alternates between the start and end of
// the arc, which ensures that there is always an
// exact half-dot at each end of the ellipse.
let going_forward = dot_index & 1 == 0;
let (next_dot_pos, leftover) = if going_forward {
let next_dot_pos =
prev_forward_pos.arc_pos + 2.0 * prev_forward_pos.diameter;
(next_dot_pos, prev_back_pos.arc_pos - next_dot_pos)
} else {
let next_dot_pos = prev_back_pos.arc_pos - 2.0 * prev_back_pos.diameter;
(next_dot_pos, next_dot_pos - prev_forward_pos.arc_pos)
};
// Use a lerp between each edge's dot
// diameter, based on the linear distance
// along the arc to get the diameter of the
// dot at this arc position.
let t = next_dot_pos / self.ellipse.total_arc_length;
let dot_diameter = lerp(self.widths.width, self.widths.height, t);
// If we can't fit a dot, bail out.
if leftover < dot_diameter {
leftover_arc_length = leftover;
break;
}
// We can place a dot!
let dot = DotInfo::new(next_dot_pos, dot_diameter);
if going_forward {
forward_dots.push(dot);
} else {
back_dots.push(dot);
}
}
// Now step through the dots, and distribute any extra
// leftover space on the arc between them evenly. Once
// the final arc position is determined, generate the correct
// arc positions and angles that get passed to the clip shader.
let number_of_dots = forward_dots.len() + back_dots.len();
let extra_space_per_dot = leftover_arc_length / (number_of_dots - 1) as f32;
let create_dot_data = |ellipse: &Ellipse<DevicePixel>, arc_length: f32, radius: f32| -> [f32; 8] {
// Represents the GPU data for drawing a single dot to a clip mask. The order
// these are specified must stay in sync with the way this data is read in the
// dot clip shader.
let theta = ellipse.find_angle_for_arc_length(arc_length);
let (center, _) = ellipse.get_point_and_tangent(theta);
let center = DevicePoint::new(
outer.x + clip_sign.x * (self.radius.width - center.x),
outer.y + clip_sign.y * (self.radius.height - center.y),
);
[center.x, center.y, radius, 0.0, 0.0, 0.0, 0.0, 0.0]
};
dot_dash_data.reserve(forward_dots.len() + back_dots.len());
for (i, dot) in forward_dots.iter().enumerate() {
let extra_dist = i as f32 * extra_space_per_dot;
let dot_data = create_dot_data(&self.ellipse, dot.arc_pos + extra_dist, 0.5 * dot.diameter);
dot_dash_data.push(dot_data);
}
for (i, dot) in back_dots.iter().enumerate() {
let extra_dist = i as f32 * extra_space_per_dot;
let dot_data = create_dot_data(&self.ellipse, dot.arc_pos - extra_dist, 0.5 * dot.diameter);
dot_dash_data.push(dot_data);
}
}
}
dot_dash_data
instances.reserve(number_of_dots);
for (i, dot) in forward_dots.iter().enumerate() {
let extra_dist = i as f32 * extra_space_per_dot;
instances.push(BorderInstance {
flags: base_instance.flags | ((BorderClipKind::Dot as i32) << 24),
clip_params: create_dot_data(dot.arc_pos + extra_dist, 0.5 * dot.diameter),
.. *base_instance
});
}
for (i, dot) in back_dots.iter().enumerate() {
let extra_dist = i as f32 * extra_space_per_dot;
instances.push(BorderInstance {
flags: base_instance.flags | ((BorderClipKind::Dot as i32) << 24),
clip_params: create_dot_data(dot.arc_pos - extra_dist, 0.5 * dot.diameter),
.. *base_instance
});
}
Ok(())
}
#[derive(Copy, Clone, Debug)]
@ -1042,39 +1030,30 @@ fn add_segment(
warn!("TODO: Handle a corner with dotted / dashed transition.");
}
let clip_kind = match style0 {
BorderStyle::Dashed => Some(BorderClipKind::DashCorner),
BorderStyle::Dotted => Some(BorderClipKind::Dot),
_ => None,
};
match clip_kind {
Some(clip_kind) => {
let clip_source = BorderCornerClipSource::new(
let dashed_or_dotted_corner = match style0 {
BorderStyle::Dashed => {
write_dashed_corner_instances(
radius,
widths,
clip_kind,
);
// TODO(gw): Restructure the BorderCornerClipSource code
// so that we don't allocate a Vec here.
let clip_list = clip_source.write(segment);
if clip_list.is_empty() {
instances.push(base_instance);
} else {
for params in clip_list {
instances.push(BorderInstance {
flags: base_flags | ((clip_kind as i32) << 24),
clip_params: params,
..base_instance
});
}
}
segment,
&base_instance,
instances,
)
}
None => {
instances.push(base_instance);
BorderStyle::Dotted => {
write_dotted_corner_instances(
radius,
widths,
segment,
&base_instance,
instances,
)
}
_ => Err(()),
};
if dashed_or_dotted_corner.is_err() {
instances.push(base_instance);
}
}
BorderSegment::Top |

Просмотреть файл

@ -100,6 +100,7 @@ pub struct PictureContext {
pub struct PictureState {
pub tasks: Vec<RenderTaskId>,
pub has_non_root_coord_system: bool,
pub is_cacheable: bool,
pub local_rect_changed: bool,
pub map_local_to_pic: SpaceMapper<LayoutPixel, PicturePixel>,
pub map_pic_to_world: SpaceMapper<PicturePixel, WorldPixel>,

Просмотреть файл

@ -291,6 +291,7 @@ impl PicturePrimitive {
let state = PictureState {
tasks: Vec::new(),
has_non_root_coord_system: false,
is_cacheable: true,
local_rect_changed: false,
raster_spatial_node_index,
surface_spatial_node_index,
@ -472,7 +473,8 @@ impl PicturePrimitive {
// anyway. In the future we should relax this a bit, so that we can
// cache tasks with complex coordinate systems if we detect the
// relevant transforms haven't changed from frame to frame.
let surface = if pic_state_for_children.has_non_root_coord_system {
let surface = if pic_state_for_children.has_non_root_coord_system ||
!pic_state_for_children.is_cacheable {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,

Просмотреть файл

@ -1651,6 +1651,10 @@ impl PrimitiveStore {
Some(pic_rect)
};
if !pic_state_for_children.is_cacheable {
pic_state.is_cacheable = false;
}
// Restore the dependencies (borrow check dance)
let prim = &mut self.primitives[prim_index.0];
let (new_local_rect, clip_node_collector) = prim
@ -1677,6 +1681,10 @@ impl PrimitiveStore {
let prim = &mut self.primitives[prim_index.0];
if !prim.is_cacheable(frame_state.resource_cache) {
pic_state.is_cacheable = false;
}
if is_passthrough {
prim.metadata.clipped_world_rect = Some(pic_state.map_pic_to_world.bounds);
} else {

Просмотреть файл

@ -1 +1 @@
70edb5f8a75ea1e1440ba7984cc42df9eb05ae69
0f142521b86f201a0f0957cc852aa14923ebfc73

Просмотреть файл

@ -365,11 +365,12 @@ ClippedImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
return false;
}
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
ClippedImage::GetImageContainerAtSize(LayerManager* aManager,
const IntSize& aSize,
NS_IMETHODIMP_(ImgDrawResult)
ClippedImage::GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
uint32_t aFlags,
layers::ImageContainer** aOutContainer)
{
// XXX(seth): We currently don't have a way of clipping the result of
// GetImageContainer. We work around this by always returning null, but if it
@ -378,11 +379,11 @@ ClippedImage::GetImageContainerAtSize(LayerManager* aManager,
// that method for performance reasons.
if (!ShouldClip()) {
return InnerImage()->GetImageContainerAtSize(aManager, aSize,
aSVGContext, aFlags);
return InnerImage()->GetImageContainerAtSize(aManager, aSize, aSVGContext,
aFlags, aOutContainer);
}
return nullptr;
return ImgDrawResult::NOT_SUPPORTED;
}
static bool

Просмотреть файл

@ -51,11 +51,12 @@ public:
IsImageContainerAvailableAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
NS_IMETHOD_(ImgDrawResult)
GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags) override;
uint32_t aFlags,
layers::ImageContainer** aOutContainer) override;
NS_IMETHOD_(ImgDrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

Просмотреть файл

@ -234,13 +234,14 @@ DynamicImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
return false;
}
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
DynamicImage::GetImageContainerAtSize(LayerManager* aManager,
const IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
NS_IMETHODIMP_(ImgDrawResult)
DynamicImage::GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags,
layers::ImageContainer** aContainer)
{
return nullptr;
return ImgDrawResult::NOT_SUPPORTED;
}
NS_IMETHODIMP_(ImgDrawResult)

Просмотреть файл

@ -77,18 +77,19 @@ FrozenImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
return false;
}
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
NS_IMETHODIMP_(ImgDrawResult)
FrozenImage::GetImageContainerAtSize(layers::LayerManager* aManager,
const IntSize& aSize,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
uint32_t aFlags,
layers::ImageContainer** aOutContainer)
{
// XXX(seth): GetImageContainer does not currently support anything but the
// current frame. We work around this by always returning null, but if it ever
// turns out that FrozenImage is widely used on codepaths that can actually
// benefit from GetImageContainer, it would be a good idea to fix that method
// for performance reasons.
return nullptr;
return ImgDrawResult::NOT_SUPPORTED;
}
NS_IMETHODIMP_(ImgDrawResult)

Просмотреть файл

@ -50,11 +50,12 @@ public:
IsImageContainerAvailableAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
NS_IMETHOD_(ImgDrawResult)
GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags) override;
uint32_t aFlags,
layers::ImageContainer** aOutContainer) override;
NS_IMETHOD_(ImgDrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

Просмотреть файл

@ -104,11 +104,12 @@ ImageResource::SetCurrentImage(ImageContainer* aContainer,
}
}
already_AddRefed<ImageContainer>
ImgDrawResult
ImageResource::GetImageContainerImpl(LayerManager* aManager,
const IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
uint32_t aFlags,
ImageContainer** aOutContainer)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aManager);
@ -119,11 +120,15 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
== FLAG_NONE,
"Unsupported flag passed to GetImageContainer");
IntSize size = GetImageContainerSize(aManager, aSize, aFlags);
if (size.IsEmpty()) {
return nullptr;
ImgDrawResult drawResult;
IntSize size;
Tie(drawResult, size) = GetImageContainerSize(aManager, aSize, aFlags);
if (drawResult != ImgDrawResult::SUCCESS) {
return drawResult;
}
MOZ_ASSERT(!size.IsEmpty());
if (mAnimationConsumers == 0) {
SendOnUnlockedDraw(aFlags);
}
@ -155,7 +160,8 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
case ImgDrawResult::SUCCESS:
case ImgDrawResult::BAD_IMAGE:
case ImgDrawResult::BAD_ARGS:
return container.forget();
container.forget(aOutContainer);
return entry->mLastDrawResult;
case ImgDrawResult::NOT_READY:
case ImgDrawResult::INCOMPLETE:
case ImgDrawResult::TEMPORARY_ERROR:
@ -165,7 +171,8 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
// Unused by GetFrameInternal
default:
MOZ_ASSERT_UNREACHABLE("Unhandled ImgDrawResult type!");
return container.forget();
container.forget(aOutContainer);
return entry->mLastDrawResult;
}
}
@ -173,7 +180,6 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
NotifyDrawingObservers();
#endif
ImgDrawResult drawResult;
IntSize bestSize;
RefPtr<SourceSurface> surface;
Tie(drawResult, bestSize, surface) =
@ -212,7 +218,8 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
case ImgDrawResult::SUCCESS:
case ImgDrawResult::BAD_IMAGE:
case ImgDrawResult::BAD_ARGS:
return container.forget();
container.forget(aOutContainer);
return entry->mLastDrawResult;
case ImgDrawResult::NOT_READY:
case ImgDrawResult::INCOMPLETE:
case ImgDrawResult::TEMPORARY_ERROR:
@ -223,7 +230,8 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
// Unused by GetFrameInternal
default:
MOZ_ASSERT_UNREACHABLE("Unhandled DrawResult type!");
return container.forget();
container.forget(aOutContainer);
return entry->mLastDrawResult;
}
}
break;
@ -245,7 +253,8 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
SetCurrentImage(container, surface, true);
entry->mLastDrawResult = drawResult;
return container.forget();
container.forget(aOutContainer);
return drawResult;
}
void

Просмотреть файл

@ -353,18 +353,19 @@ protected:
* the same as the size of the surface in the image container, but it is the
* best effort estimate.
*/
virtual gfx::IntSize GetImageContainerSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
uint32_t aFlags)
virtual Tuple<ImgDrawResult, gfx::IntSize>
GetImageContainerSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
uint32_t aFlags)
{
return gfx::IntSize(0, 0);
return MakeTuple(ImgDrawResult::NOT_SUPPORTED, gfx::IntSize(0, 0));
}
already_AddRefed<layers::ImageContainer>
GetImageContainerImpl(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags);
ImgDrawResult GetImageContainerImpl(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags,
layers::ImageContainer** aContainer);
void UpdateImageContainer();

Просмотреть файл

@ -222,14 +222,15 @@ ImageWrapper::IsImageContainerAvailableAtSize(LayerManager* aManager,
return mInnerImage->IsImageContainerAvailableAtSize(aManager, aSize, aFlags);
}
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
ImageWrapper::GetImageContainerAtSize(LayerManager* aManager,
const IntSize& aSize,
NS_IMETHODIMP_(ImgDrawResult)
ImageWrapper::GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
uint32_t aFlags,
layers::ImageContainer** aOutContainer)
{
return mInnerImage->GetImageContainerAtSize(aManager, aSize,
aSVGContext, aFlags);
return mInnerImage->GetImageContainerAtSize(aManager, aSize, aSVGContext,
aFlags, aOutContainer);
}
NS_IMETHODIMP_(ImgDrawResult)

Просмотреть файл

@ -51,6 +51,9 @@ namespace image {
* permanent condition.
*
* BAD_ARGS: We failed to draw because bad arguments were passed to draw().
*
* NOT_SUPPORTED: The requested operation is not supported, but the image is
* otherwise valid.
*/
enum class MOZ_MUST_USE_TYPE ImgDrawResult : uint8_t
{
@ -61,7 +64,8 @@ enum class MOZ_MUST_USE_TYPE ImgDrawResult : uint8_t
NOT_READY,
TEMPORARY_ERROR,
BAD_IMAGE,
BAD_ARGS
BAD_ARGS,
NOT_SUPPORTED
};
/**
@ -79,6 +83,11 @@ operator&(const ImgDrawResult aLeft, const ImgDrawResult aRight)
return aRight;
}
if (aLeft == ImgDrawResult::NOT_SUPPORTED ||
aRight == ImgDrawResult::NOT_SUPPORTED) {
return ImgDrawResult::NOT_SUPPORTED;
}
if ((aLeft == ImgDrawResult::BAD_IMAGE ||
aLeft == ImgDrawResult::SUCCESS_NOT_COMPLETE) &&
aRight != ImgDrawResult::SUCCESS &&

Просмотреть файл

@ -182,11 +182,12 @@ OrientedImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
return false;
}
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
OrientedImage::GetImageContainerAtSize(LayerManager* aManager,
const IntSize& aSize,
NS_IMETHODIMP_(ImgDrawResult)
OrientedImage::GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
uint32_t aFlags,
layers::ImageContainer** aOutContainer)
{
// XXX(seth): We currently don't have a way of orienting the result of
// GetImageContainer. We work around this by always returning null, but if it
@ -195,11 +196,11 @@ OrientedImage::GetImageContainerAtSize(LayerManager* aManager,
// that method for performance reasons.
if (mOrientation.IsIdentity()) {
return InnerImage()->GetImageContainerAtSize(aManager, aSize,
aSVGContext, aFlags);
return InnerImage()->GetImageContainerAtSize(aManager, aSize, aSVGContext,
aFlags, aOutContainer);
}
return nullptr;
return ImgDrawResult::NOT_SUPPORTED;
}
struct MatrixBuilder

Просмотреть файл

@ -48,11 +48,12 @@ public:
IsImageContainerAvailableAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
NS_IMETHOD_(ImgDrawResult)
GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags) override;
uint32_t aFlags,
layers::ImageContainer** aOutContainer) override;
NS_IMETHOD_(ImgDrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

Просмотреть файл

@ -627,20 +627,34 @@ RasterImage::GetFrameInternal(const IntSize& aSize,
return MakeTuple(ImgDrawResult::SUCCESS, suggestedSize, std::move(surface));
}
IntSize
Tuple<ImgDrawResult, IntSize>
RasterImage::GetImageContainerSize(LayerManager* aManager,
const IntSize& aSize,
uint32_t aFlags)
{
if (!IsImageContainerAvailableAtSize(aManager, aSize, aFlags)) {
return IntSize(0, 0);
if (!mHasSize) {
return MakeTuple(ImgDrawResult::NOT_READY, IntSize(0, 0));
}
if (aSize.IsEmpty()) {
return MakeTuple(ImgDrawResult::BAD_ARGS, IntSize(0, 0));
}
// We check the minimum size because while we support downscaling, we do not
// support upscaling. If aSize > mSize, we will never give a larger surface
// than mSize. If mSize > aSize, and mSize > maxTextureSize, we still want to
// use image containers if aSize <= maxTextureSize.
int32_t maxTextureSize = aManager->GetMaxTextureSize();
if (min(mSize.width, aSize.width) > maxTextureSize ||
min(mSize.height, aSize.height) > maxTextureSize) {
return MakeTuple(ImgDrawResult::NOT_SUPPORTED, IntSize(0, 0));
}
if (!CanDownscaleDuringDecode(aSize, aFlags)) {
return mSize;
return MakeTuple(ImgDrawResult::SUCCESS, mSize);
}
return aSize;
return MakeTuple(ImgDrawResult::SUCCESS, aSize);
}
NS_IMETHODIMP_(bool)
@ -652,7 +666,15 @@ RasterImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
return GetImageContainerImpl(aManager, mSize, Nothing(), aFlags);
RefPtr<ImageContainer> container;
ImgDrawResult drawResult =
GetImageContainerImpl(aManager, mSize, Nothing(), aFlags,
getter_AddRefs(container));
// We silence the unused warning here because anything that needs the draw
// result should be using GetImageContainerAtSize, not GetImageContainer.
(void)drawResult;
return container.forget();
}
NS_IMETHODIMP_(bool)
@ -674,16 +696,18 @@ RasterImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
return true;
}
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
RasterImage::GetImageContainerAtSize(LayerManager* aManager,
const IntSize& aSize,
NS_IMETHODIMP_(ImgDrawResult)
RasterImage::GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
uint32_t aFlags,
layers::ImageContainer** aOutContainer)
{
// We do not pass in the given SVG context because in theory it could differ
// between calls, but actually have no impact on the actual contents of the
// image container.
return GetImageContainerImpl(aManager, aSize, Nothing(), aFlags);
return GetImageContainerImpl(aManager, aSize, Nothing(),
aFlags, aOutContainer);
}
size_t

Просмотреть файл

@ -312,9 +312,10 @@ private:
uint32_t aWhichFrame,
uint32_t aFlags) override;
gfx::IntSize GetImageContainerSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
uint32_t aFlags) override;
Tuple<ImgDrawResult, gfx::IntSize>
GetImageContainerSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
uint32_t aFlags) override;
//////////////////////////////////////////////////////////////////////////////
// Decoding.

Просмотреть файл

@ -849,16 +849,31 @@ VectorImage::GetFrameInternal(const IntSize& aSize,
}
//******************************************************************************
IntSize
Tuple<ImgDrawResult, IntSize>
VectorImage::GetImageContainerSize(LayerManager* aManager,
const IntSize& aSize,
uint32_t aFlags)
{
if (!IsImageContainerAvailableAtSize(aManager, aSize, aFlags)) {
return IntSize(0, 0);
if (mError) {
return MakeTuple(ImgDrawResult::BAD_IMAGE, IntSize(0, 0));
}
return aSize;
if (!mIsFullyLoaded) {
return MakeTuple(ImgDrawResult::NOT_READY, IntSize(0, 0));
}
if (mHaveAnimations ||
aManager->GetBackendType() != LayersBackend::LAYERS_WR) {
return MakeTuple(ImgDrawResult::NOT_SUPPORTED, IntSize(0, 0));
}
// We don't need to check if the size is too big since we only support
// WebRender backends.
if (aSize.IsEmpty()) {
return MakeTuple(ImgDrawResult::BAD_ARGS, IntSize(0, 0));
}
return MakeTuple(ImgDrawResult::SUCCESS, aSize);
}
NS_IMETHODIMP_(bool)
@ -893,11 +908,12 @@ VectorImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
}
//******************************************************************************
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
VectorImage::GetImageContainerAtSize(LayerManager* aManager,
const IntSize& aSize,
NS_IMETHODIMP_(ImgDrawResult)
VectorImage::GetImageContainerAtSize(layers::LayerManager* aManager,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
uint32_t aFlags,
layers::ImageContainer** aOutContainer)
{
Maybe<SVGImageContext> newSVGContext;
MaybeRestrictSVGContext(newSVGContext, aSVGContext, aFlags);
@ -910,7 +926,7 @@ VectorImage::GetImageContainerAtSize(LayerManager* aManager,
FLAG_FORCE_PRESERVEASPECTRATIO_NONE);
return GetImageContainerImpl(aManager, aSize,
newSVGContext ? newSVGContext : aSVGContext,
flags);
flags, aOutContainer);
}
bool

Просмотреть файл

@ -87,9 +87,10 @@ private:
uint32_t aWhichFrame,
uint32_t aFlags) override;
IntSize GetImageContainerSize(layers::LayerManager* aManager,
const IntSize& aSize,
uint32_t aFlags) override;
Tuple<ImgDrawResult, IntSize>
GetImageContainerSize(layers::LayerManager* aManager,
const IntSize& aSize,
uint32_t aFlags) override;
/// Attempt to find a matching cached surface in the SurfaceCache.
already_AddRefed<SourceSurface>

Просмотреть файл

@ -57,6 +57,7 @@ native nsIntRectByVal(nsIntRect);
native nsSize(nsSize);
[ptr] native nsIFrame(nsIFrame);
native TempRefImageContainer(already_AddRefed<mozilla::layers::ImageContainer>);
[ptr] native ImageContainer(mozilla::layers::ImageContainer);
[ref] native ImageRegion(mozilla::image::ImageRegion);
[ptr] native LayerManager(mozilla::layers::LayerManager);
native Orientation(mozilla::image::Orientation);
@ -295,15 +296,6 @@ interface imgIContainer : nsISupports
[noscript, notxpcom] TempRefImageContainer getImageContainer(in LayerManager aManager,
in uint32_t aFlags);
/**
* @return true if getImageContainer() is expected to return a valid
* ImageContainer when passed the given @Manager, @Size and @Flags
* parameters.
*/
[noscript, notxpcom] boolean isImageContainerAvailableAtSize(in LayerManager aManager,
[const] in nsIntSize aSize,
in uint32_t aFlags);
/**
* Attempts to create an ImageContainer (and Image) containing the current
* frame at the given size. Match the requested size is best effort; it's
@ -322,13 +314,24 @@ interface imgIContainer : nsISupports
* @param aFlags Decoding / drawing flags (in other words, FLAG_* flags).
* Currently only FLAG_SYNC_DECODE and FLAG_SYNC_DECODE_IF_FAST
* are supported.
* @return An ImageContainer for the current frame, or nullptr if one could
* not be created.
* @param aContainer Return value for ImageContainer for the current frame.
* May be null depending on the draw result.
* @return The draw result for the current frame.
*/
[noscript, notxpcom] TempRefImageContainer getImageContainerAtSize(in LayerManager aManager,
[const] in nsIntSize aSize,
[const] in MaybeSVGImageContext aSVGContext,
in uint32_t aFlags);
[noscript, notxpcom] ImgDrawResult getImageContainerAtSize(in LayerManager aManager,
[const] in nsIntSize aSize,
[const] in MaybeSVGImageContext aSVGContext,
in uint32_t aFlags,
out ImageContainer aOutContainer);
/**
* @return true if getImageContainer() is expected to return a valid
* ImageContainer when passed the given @Manager, @Size and @Flags
* parameters.
*/
[noscript, notxpcom] boolean isImageContainerAvailableAtSize(in LayerManager aManager,
[const] in nsIntSize aSize,
in uint32_t aFlags);
/**
* Draw the requested frame of this image onto the context specified.

Просмотреть файл

@ -68,14 +68,17 @@ TEST_F(ImageContainers, RasterImageContainer)
EXPECT_EQ(testCase.mSize.height, containerSize.height);
// Upscaling should give the native size.
ImgDrawResult drawResult;
IntSize requestedSize = testCase.mSize;
requestedSize.Scale(2, 2);
RefPtr<layers::ImageContainer> upscaleContainer =
image->GetImageContainerAtSize(layerManager,
requestedSize,
Nothing(),
imgIContainer::FLAG_SYNC_DECODE |
imgIContainer::FLAG_HIGH_QUALITY_SCALING);
RefPtr<layers::ImageContainer> upscaleContainer;
drawResult = image->GetImageContainerAtSize(layerManager,
requestedSize,
Nothing(),
imgIContainer::FLAG_SYNC_DECODE |
imgIContainer::FLAG_HIGH_QUALITY_SCALING,
getter_AddRefs(upscaleContainer));
EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
ASSERT_TRUE(upscaleContainer != nullptr);
containerSize = upscaleContainer->GetCurrentSize();
EXPECT_EQ(testCase.mSize.width, containerSize.width);
@ -85,21 +88,26 @@ TEST_F(ImageContainers, RasterImageContainer)
requestedSize = testCase.mSize;
requestedSize.width /= 2;
requestedSize.height /= 2;
RefPtr<layers::ImageContainer> downscaleContainer =
image->GetImageContainerAtSize(layerManager,
requestedSize,
Nothing(),
imgIContainer::FLAG_SYNC_DECODE |
imgIContainer::FLAG_HIGH_QUALITY_SCALING);
RefPtr<layers::ImageContainer> downscaleContainer;
drawResult = image->GetImageContainerAtSize(layerManager,
requestedSize,
Nothing(),
imgIContainer::FLAG_SYNC_DECODE |
imgIContainer::FLAG_HIGH_QUALITY_SCALING,
getter_AddRefs(downscaleContainer));
EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
ASSERT_TRUE(downscaleContainer != nullptr);
containerSize = downscaleContainer->GetCurrentSize();
EXPECT_EQ(requestedSize.width, containerSize.width);
EXPECT_EQ(requestedSize.height, containerSize.height);
// Get at native size again. Should give same container.
RefPtr<layers::ImageContainer> againContainer =
image->GetImageContainerAtSize(layerManager,
testCase.mSize,
Nothing(),
imgIContainer::FLAG_SYNC_DECODE);
RefPtr<layers::ImageContainer> againContainer;
drawResult = image->GetImageContainerAtSize(layerManager,
testCase.mSize,
Nothing(),
imgIContainer::FLAG_SYNC_DECODE,
getter_AddRefs(againContainer));
EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
ASSERT_EQ(nativeContainer.get(), againContainer.get());
}

Просмотреть файл

@ -2660,8 +2660,11 @@ BytecodeEmitter::emitSwitch(SwitchStatement* switchStmt)
NumericLiteral* literal = &caseValue->as<NumericLiteral>();
#ifdef DEBUG
// Use NumberEqualsInt32 here because switches compare using
// strict equality, which will equate -0 and +0. In contrast
// NumberIsInt32 would return false for -0.
int32_t v;
MOZ_ASSERT(mozilla::NumberIsInt32(literal->value(), &v));
MOZ_ASSERT(mozilla::NumberEqualsInt32(literal->value(), &v));
#endif
int32_t i = int32_t(literal->value());

Просмотреть файл

@ -1838,6 +1838,16 @@ CreateDependentString::generate(MacroAssembler& masm, const JSAtomState& names,
masm.bind(&nonEmpty);
// Complete matches use the base string.
Label nonBaseStringMatch;
masm.branchTest32(Assembler::NonZero, temp2_, temp2_, &nonBaseStringMatch);
masm.branch32(Assembler::NotEqual, Address(base, JSString::offsetOfLength()), temp1_,
&nonBaseStringMatch);
masm.movePtr(base, string_);
masm.jump(&done);
masm.bind(&nonBaseStringMatch);
Label notInline;
int32_t maxInlineLength = encoding_ == CharEncoding::Latin1
@ -1852,6 +1862,25 @@ CreateDependentString::generate(MacroAssembler& masm, const JSAtomState& names,
? JSThinInlineString::MAX_LENGTH_LATIN1
: JSThinInlineString::MAX_LENGTH_TWO_BYTE;
masm.branch32(Assembler::Above, temp1_, Imm32(maxThinInlineLength), &fatInline);
if (encoding_ == CharEncoding::Latin1) {
// One character Latin-1 strings can be loaded directly from the
// static strings table.
Label thinInline;
masm.branch32(Assembler::Above, temp1_, Imm32(1), &thinInline);
{
static_assert(StaticStrings::UNIT_STATIC_LIMIT -1 == JSString::MAX_LATIN1_CHAR,
"Latin-1 strings can be loaded from static strings");
masm.loadStringChars(base, temp1_, encoding_);
masm.loadChar(temp1_, temp2_, temp1_, encoding_);
masm.movePtr(ImmPtr(&runtime->staticStrings().unitStaticTable), string_);
masm.loadPtr(BaseIndex(string_, temp1_, ScalePointer), string_);
masm.jump(&done);
}
masm.bind(&thinInline);
}
{
newGCString(FallbackKind::InlineString);
masm.jump(&stringAllocated);

Просмотреть файл

@ -177,14 +177,21 @@ nsDisplayFieldSetBorder::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder
rect = nsRect(offset, frame->GetRect().Size());
}
return nsCSSRendering::CreateWebRenderCommandsForBorder(this,
mFrame,
rect,
aBuilder,
aResources,
aSc,
aManager,
aDisplayListBuilder);
ImgDrawResult drawResult =
nsCSSRendering::CreateWebRenderCommandsForBorder(this,
mFrame,
rect,
aBuilder,
aResources,
aSc,
aManager,
aDisplayListBuilder);
if (drawResult == ImgDrawResult::NOT_SUPPORTED) {
return false;
}
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, drawResult);
return true;
};
void

Просмотреть файл

@ -241,7 +241,7 @@ public:
MOZ_ASSERT(IsTextType());
}
bool
ImgDrawResult
CreateWebRenderCommands(nsDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
@ -291,7 +291,7 @@ public:
IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags);
private:
bool
ImgDrawResult
CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
@ -349,7 +349,7 @@ private:
int32_t mListStyleType;
};
bool
ImgDrawResult
BulletRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
@ -360,14 +360,19 @@ BulletRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
if (IsImageType()) {
return CreateWebRenderCommandsForImage(aItem, aBuilder, aResources,
aSc, aManager, aDisplayListBuilder);
} else if (IsPathType()) {
return CreateWebRenderCommandsForPath(aItem, aBuilder, aResources,
aSc, aManager, aDisplayListBuilder);
}
bool success;
if (IsPathType()) {
success = CreateWebRenderCommandsForPath(aItem, aBuilder, aResources, aSc,
aManager, aDisplayListBuilder);
} else {
MOZ_ASSERT(IsTextType());
return CreateWebRenderCommandsForText(aItem, aBuilder, aResources, aSc,
aManager, aDisplayListBuilder);
success = CreateWebRenderCommandsForText(aItem, aBuilder, aResources, aSc,
aManager, aDisplayListBuilder);
}
return success ? ImgDrawResult::SUCCESS : ImgDrawResult::NOT_SUPPORTED;
}
ImgDrawResult
@ -454,7 +459,7 @@ BulletRenderer::IsImageContainerAvailable(layers::LayerManager* aManager, uint32
return mImage->IsImageContainerAvailable(aManager, aFlags);
}
bool
ImgDrawResult
BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
@ -479,10 +484,13 @@ BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
gfx::IntSize decodeSize =
nsLayoutUtils::ComputeImageContainerDrawingParameters(mImage, aItem->Frame(), destRect,
aSc, flags, svgContext);
RefPtr<layers::ImageContainer> container =
mImage->GetImageContainerAtSize(aManager, decodeSize, svgContext, flags);
RefPtr<layers::ImageContainer> container;
ImgDrawResult drawResult =
mImage->GetImageContainerAtSize(aManager, decodeSize, svgContext,
flags, getter_AddRefs(container));
if (!container) {
return false;
return drawResult;
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
@ -491,7 +499,7 @@ BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
if (key.isNothing()) {
return true; // Nothing to do
return drawResult;
}
wr::LayoutRect dest = wr::ToRoundedLayoutRect(destRect);
@ -499,7 +507,7 @@ BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
aBuilder.PushImage(
dest, dest, !aItem->BackfaceIsHidden(), rendering, key.value());
return true;
return drawResult;
}
bool
@ -665,8 +673,15 @@ nsDisplayBullet::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
return false;
}
return br->CreateWebRenderCommands(this, aBuilder, aResources, aSc,
aManager, aDisplayListBuilder);
ImgDrawResult drawResult =
br->CreateWebRenderCommands(this, aBuilder, aResources, aSc,
aManager, aDisplayListBuilder);
if (drawResult == ImgDrawResult::NOT_SUPPORTED) {
return false;
}
nsDisplayBulletGeometry::UpdateDrawResult(this, drawResult);
return true;
}
void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,

Просмотреть файл

@ -1814,16 +1814,60 @@ nsDisplayImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilde
IntSize decodeSize =
nsLayoutUtils::ComputeImageContainerDrawingParameters(mImage, mFrame, destRect,
aSc, flags, svgContext);
RefPtr<ImageContainer> container =
mImage->GetImageContainerAtSize(aManager, decodeSize, svgContext, flags);
if (!container) {
return false;
RefPtr<layers::ImageContainer> container;
ImgDrawResult drawResult =
mImage->GetImageContainerAtSize(aManager, decodeSize, svgContext,
flags, getter_AddRefs(container));
// While we got a container, it may not contain a fully decoded surface. If
// that is the case, and we have an image we were previously displaying which
// has a fully decoded surface, then we should prefer the previous image.
bool updatePrevImage = false;
switch (drawResult) {
case ImgDrawResult::NOT_READY:
case ImgDrawResult::INCOMPLETE:
case ImgDrawResult::TEMPORARY_ERROR:
if (mPrevImage && mPrevImage != mImage) {
RefPtr<ImageContainer> prevContainer;
drawResult = mPrevImage->GetImageContainerAtSize(aManager, decodeSize,
svgContext, flags,
getter_AddRefs(prevContainer));
if (prevContainer && drawResult == ImgDrawResult::SUCCESS) {
container = std::move(prevContainer);
break;
}
// Previous image was unusable; we can forget about it.
updatePrevImage = true;
}
break;
case ImgDrawResult::NOT_SUPPORTED:
return false;
default:
updatePrevImage = mPrevImage != mImage;
break;
}
// The previous image was not used, and is different from the current image.
// We should forget about it. We need to update the frame as well because the
// display item may get recreated.
if (updatePrevImage) {
mPrevImage = mImage;
if (mFrame->IsImageFrame()) {
nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
f->mPrevImage = f->mImage;
}
}
// If the image container is empty, we don't want to fallback. Any other
// failure will be due to resource constraints and fallback is unlikely to
// help us. Hence we can ignore the return value from PushImage.
aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources, aSc, destRect);
if (container) {
aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources, aSc, destRect);
}
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, drawResult);
return true;
}

Просмотреть файл

@ -759,7 +759,7 @@ nsCSSRendering::CreateBorderRenderer(nsPresContext* aPresContext,
aSkipSides);
}
bool
ImgDrawResult
nsCSSRendering::CreateWebRenderCommandsForBorder(
nsDisplayItem* aItem,
nsIFrame* aForFrame,
@ -783,12 +783,12 @@ nsCSSRendering::CreateWebRenderCommandsForBorder(
&borderIsEmpty,
aForFrame->GetSkipSides());
if (borderIsEmpty) {
return true;
return ImgDrawResult::SUCCESS;
}
if (br) {
br->CreateWebRenderCommands(aItem, aBuilder, aResources, aSc);
return true;
return ImgDrawResult::SUCCESS;
}
}
@ -798,7 +798,7 @@ nsCSSRendering::CreateWebRenderCommandsForBorder(
// Filter out unsupported image/border types
if (!image) {
return false;
return ImgDrawResult::NOT_SUPPORTED;
}
// All this code bitrotted too much (but is almost right); disabled for now.
@ -807,14 +807,14 @@ nsCSSRendering::CreateWebRenderCommandsForBorder(
// FIXME(1409774): fix this: image->GetType() == eStyleImageType_Gradient;
if (!imageTypeSupported) {
return false;
return ImgDrawResult::NOT_SUPPORTED;
}
if (styleBorder->mBorderImageRepeatH == StyleBorderImageRepeat::Round ||
styleBorder->mBorderImageRepeatH == StyleBorderImageRepeat::Space ||
styleBorder->mBorderImageRepeatV == StyleBorderImageRepeat::Round ||
styleBorder->mBorderImageRepeatV == StyleBorderImageRepeat::Space) {
return false;
return ImgDrawResult::NOT_SUPPORTED;
}
uint32_t flags = 0;
@ -835,18 +835,11 @@ nsCSSRendering::CreateWebRenderCommandsForBorder(
&result);
if (!bir) {
return false;
return result;
}
if (image->GetType() == eStyleImageType_Image &&
!bir->mImageRenderer.IsImageContainerAvailable(aManager, flags)) {
return false;
}
bir->CreateWebRenderCommands(
return bir->CreateWebRenderCommands(
aItem, aForFrame, aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
return true;
}
static nsCSSBorderRenderer

Просмотреть файл

@ -233,7 +233,7 @@ struct nsCSSRendering
const nsRect& aBorderArea,
mozilla::ComputedStyle* aComputedStyle);
static bool CreateWebRenderCommandsForBorder(
static ImgDrawResult CreateWebRenderCommandsForBorder(
nsDisplayItem* aItem,
nsIFrame* aForFrame,
const nsRect& aBorderArea,

Просмотреть файл

@ -3801,7 +3801,7 @@ nsCSSBorderImageRenderer::DrawBorderImage(nsPresContext* aPresContext,
return result;
}
void
ImgDrawResult
nsCSSBorderImageRenderer::CreateWebRenderCommands(
nsDisplayItem* aItem,
nsIFrame* aForFrame,
@ -3812,7 +3812,7 @@ nsCSSBorderImageRenderer::CreateWebRenderCommands(
nsDisplayListBuilder* aDisplayListBuilder)
{
if (!mImageRenderer.IsReady()) {
return;
return ImgDrawResult::NOT_READY;
}
float widths[4];
@ -3838,6 +3838,7 @@ nsCSSBorderImageRenderer::CreateWebRenderCommands(
clip = wr::ToRoundedLayoutRect(clipRect);
}
ImgDrawResult drawResult = ImgDrawResult::SUCCESS;
switch (mImageRenderer.GetType()) {
case eStyleImageType_Image: {
uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
@ -3853,10 +3854,12 @@ nsCSSBorderImageRenderer::CreateWebRenderCommands(
gfx::IntSize decodeSize =
nsLayoutUtils::ComputeImageContainerDrawingParameters(
img, aForFrame, destRect, aSc, flags, svgContext);
RefPtr<layers::ImageContainer> container =
img->GetImageContainerAtSize(aManager, decodeSize, svgContext, flags);
RefPtr<layers::ImageContainer> container;
drawResult = img->GetImageContainerAtSize(aManager, decodeSize, svgContext,
flags, getter_AddRefs(container));
if (!container) {
return;
break;
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
@ -3872,7 +3875,7 @@ nsCSSBorderImageRenderer::CreateWebRenderCommands(
size,
Nothing());
if (key.isNothing()) {
return;
break;
}
aBuilder.PushBorderImage(
@ -3937,7 +3940,10 @@ nsCSSBorderImageRenderer::CreateWebRenderCommands(
}
default:
MOZ_ASSERT_UNREACHABLE("Unsupport border image type");
drawResult = ImgDrawResult::NOT_SUPPORTED;
}
return drawResult;
}
nsCSSBorderImageRenderer::nsCSSBorderImageRenderer(

Просмотреть файл

@ -291,7 +291,7 @@ public:
gfxContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect);
void CreateWebRenderCommands(
mozilla::image::ImgDrawResult CreateWebRenderCommands(
nsDisplayItem* aItem,
nsIFrame* aForFrame,
mozilla::wr::DisplayListBuilder& aBuilder,

Просмотреть файл

@ -4298,8 +4298,11 @@ nsDisplayBackgroundImage::CreateWebRenderCommands(
ImgDrawResult result =
nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(
params, aBuilder, aResources, aSc, aManager, this);
nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
if (result == ImgDrawResult::NOT_SUPPORTED) {
return false;
}
nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
return true;
}
@ -5537,14 +5540,22 @@ nsDisplayBorder::CreateWebRenderCommands(
{
nsRect rect = nsRect(ToReferenceFrame(), mFrame->GetSize());
return nsCSSRendering::CreateWebRenderCommandsForBorder(this,
mFrame,
rect,
aBuilder,
aResources,
aSc,
aManager,
aDisplayListBuilder);
ImgDrawResult drawResult =
nsCSSRendering::CreateWebRenderCommandsForBorder(this,
mFrame,
rect,
aBuilder,
aResources,
aSc,
aManager,
aDisplayListBuilder);
if (drawResult == ImgDrawResult::NOT_SUPPORTED) {
return false;
}
nsDisplayBorderGeometry::UpdateDrawResult(this, drawResult);
return true;
};
void

Просмотреть файл

@ -125,6 +125,9 @@ public:
static void UpdateDrawResult(nsDisplayItem* aItem,
mozilla::image::ImgDrawResult aResult)
{
MOZ_ASSERT(aResult != mozilla::image::ImgDrawResult::NOT_SUPPORTED,
"ImgDrawResult::NOT_SUPPORTED should be handled already!");
auto lastGeometry =
static_cast<T*>(mozilla::FrameLayerBuilder::GetMostRecentGeometry(aItem));
if (lastGeometry) {

Просмотреть файл

@ -602,6 +602,7 @@ nsImageRenderer::BuildWebRenderDisplayItems(
return ImgDrawResult::SUCCESS;
}
ImgDrawResult drawResult = ImgDrawResult::SUCCESS;
switch (mType) {
case eStyleImageType_Gradient: {
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
@ -641,12 +642,13 @@ nsImageRenderer::BuildWebRenderDisplayItems(
aSc,
containerFlags,
svgContext);
RefPtr<layers::ImageContainer> container =
mImageContainer->GetImageContainerAtSize(
aManager, decodeSize, svgContext, containerFlags);
RefPtr<layers::ImageContainer> container;
drawResult = mImageContainer->GetImageContainerAtSize(aManager, decodeSize, svgContext,
containerFlags, getter_AddRefs(container));
if (!container) {
NS_WARNING("Failed to get image container");
return ImgDrawResult::NOT_READY;
break;
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
@ -663,7 +665,7 @@ nsImageRenderer::BuildWebRenderDisplayItems(
Nothing());
if (key.isNothing()) {
return ImgDrawResult::NOT_READY;
break;
}
nsPoint firstTilePos = nsLayoutUtils::GetBackgroundFirstTilePos(
@ -721,8 +723,10 @@ nsImageRenderer::BuildWebRenderDisplayItems(
break;
}
return mImage->IsComplete() ? ImgDrawResult::SUCCESS
: ImgDrawResult::SUCCESS_NOT_COMPLETE;
if (!mImage->IsComplete() && drawResult == ImgDrawResult::SUCCESS) {
return ImgDrawResult::SUCCESS_NOT_COMPLETE;
}
return drawResult;
}
already_AddRefed<gfxDrawable>

Просмотреть файл

@ -418,7 +418,7 @@ nsImageBoxFrame::PaintImage(gfxContext& aRenderingContext,
hasSubRect ? &mSubRect : nullptr);
}
Maybe<ImgDrawResult>
ImgDrawResult
nsImageBoxFrame::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
@ -434,7 +434,7 @@ nsImageBoxFrame::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuild
anchorPoint,
dest);
if (!imgCon) {
return Nothing();
return result;
}
uint32_t containerFlags = imgIContainer::FLAG_ASYNC_NOTIFY;
@ -452,11 +452,13 @@ nsImageBoxFrame::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuild
gfx::IntSize decodeSize =
nsLayoutUtils::ComputeImageContainerDrawingParameters(imgCon, aItem->Frame(), fillRect,
aSc, containerFlags, svgContext);
RefPtr<layers::ImageContainer> container =
imgCon->GetImageContainerAtSize(aManager, decodeSize, svgContext, containerFlags);
RefPtr<layers::ImageContainer> container;
result = imgCon->GetImageContainerAtSize(aManager, decodeSize, svgContext,
containerFlags, getter_AddRefs(container));
if (!container) {
NS_WARNING("Failed to get image container");
return Nothing();
return result;
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
@ -465,7 +467,7 @@ nsImageBoxFrame::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuild
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
if (key.isNothing()) {
return Some(ImgDrawResult::NOT_READY);
return result;
}
wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
@ -478,7 +480,7 @@ nsImageBoxFrame::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuild
rendering,
key.value());
return Some(ImgDrawResult::SUCCESS);
return result;
}
nsRect
@ -569,13 +571,13 @@ nsDisplayXULImage::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBui
flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
}
Maybe<ImgDrawResult> result = imageFrame->
ImgDrawResult result = imageFrame->
CreateWebRenderCommands(aBuilder, aResources, aSc, aManager, this, ToReferenceFrame(), flags);
if (!result) {
if (result == ImgDrawResult::NOT_SUPPORTED) {
return false;
}
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, *result);
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
return true;
}

Просмотреть файл

@ -96,13 +96,13 @@ public:
const nsRect& aDirtyRect,
nsPoint aPt, uint32_t aFlags);
Maybe<ImgDrawResult> CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayItem* aItem,
nsPoint aPt,
uint32_t aFlags);
ImgDrawResult CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayItem* aItem,
nsPoint aPt,
uint32_t aFlags);
bool CanOptimizeToImageLayer();

Просмотреть файл

@ -22,8 +22,6 @@
#include <ostream>
#include <type_traits>
class nsCycleCollectionTraversalCallback;
namespace mozilla {
struct Nothing { };
@ -715,28 +713,6 @@ operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS)
return !(aLHS < aRHS);
}
template<typename T>
void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
Maybe<T>& aMaybe,
const char* aName,
uint32_t aFlags = 0)
{
if (aMaybe.isSome()) {
ImplCycleCollectionTraverse(aCallback, aMaybe.ref(), aName, aFlags);
}
}
template<typename T>
void
ImplCycleCollectionUnlink(Maybe<T>& aMaybe)
{
if (aMaybe.isSome()) {
ImplCycleCollectionUnlink(aMaybe.ref());
}
}
} // namespace mozilla
#endif /* mozilla_Maybe_h */

Просмотреть файл

@ -23,7 +23,7 @@ class GeckoViewNavigationContent extends GeckoViewContentModule {
where=${aWhere} flags=${aFlags}`;
if (!this.enabled) {
return Promise.resolve(false);
return false;
}
// TODO: Remove this when we have a sensible error API.

Просмотреть файл

@ -6,6 +6,7 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
ActorManagerParent: "resource://gre/modules/ActorManagerParent.jsm",
EventDispatcher: "resource://gre/modules/Messaging.jsm",
FileSource: "resource://gre/modules/L10nRegistry.jsm",
GeckoViewTelemetryController: "resource://gre/modules/GeckoViewTelemetryController.jsm",
GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
@ -121,6 +122,11 @@ GeckoViewStartup.prototype = {
let locales = Services.locale.getPackagedLocales();
const greSource = new FileSource("toolkit", locales, "resource://gre/localization/{locale}/");
L10nRegistry.registerSource(greSource);
// Listen for global EventDispatcher messages
EventDispatcher.instance.registerListener(
(aEvent, aData, aCallback) => Services.locale.setRequestedLocales([aData.languageTag]),
"GeckoView:SetLocale");
break;
}
}

Просмотреть файл

@ -0,0 +1,33 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.geckoview.test
import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.ReuseSession
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDevToolsAPI
import android.support.test.filters.MediumTest
import android.support.test.runner.AndroidJUnit4
import org.hamcrest.Matchers.*
import org.junit.Test
import org.junit.runner.RunWith
@MediumTest
@RunWith(AndroidJUnit4::class)
@WithDevToolsAPI
class LocaleTest : BaseSessionTest() {
@Test fun setLocale() {
sessionRule.runtime.getSettings().setLocale("en-GB");
val index = sessionRule.waitForChromeJS(String.format(
"(function() {" +
" return ChromeUtils.import('resource://gre/modules/Services.jsm', {})" +
" .Services.locale.getRequestedLocales().indexOf('en-GB');" +
"})()")) as Double;
assertThat("Requested locale is found", index, greaterThanOrEqualTo(0.0));
}
}

Просмотреть файл

@ -20,6 +20,7 @@ import android.support.test.filters.MediumTest
import android.support.test.runner.AndroidJUnit4
import org.hamcrest.Matchers.*
import org.junit.Assume.assumeThat
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
@ -201,6 +202,7 @@ class NavigationDelegateTest : BaseSessionTest() {
})
}
@Ignore
@Test fun redirectLoad() {
val redirectUri = if (sessionRule.env.isAutomation) {
"http://example.org/tests/robocop/robocop_blank_02.html"

Просмотреть файл

@ -79,6 +79,7 @@ class ProgressDelegateTest : BaseSessionTest() {
})
}
@Ignore
@Test fun multipleLoads() {
sessionRule.session.loadUri(UNKNOWN_HOST_URI)
sessionRule.session.loadTestPath(HELLO_HTML_PATH)

Просмотреть файл

@ -18,6 +18,8 @@ import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.geckoview.GeckoSession.TrackingProtectionDelegate;
public final class GeckoRuntimeSettings implements Parcelable {
@ -291,6 +293,17 @@ public final class GeckoRuntimeSettings implements Parcelable {
mSettings.mCrashHandler = handler;
return this;
}
/**
* Set the locale.
*
* @param languageTag The locale code in Gecko format ("en" or "en-US").
* @return The builder instance.
*/
public @NonNull Builder locale(String languageTag) {
mSettings.mLocale = languageTag;
return this;
}
}
/* package */ GeckoRuntime runtime;
@ -360,6 +373,7 @@ public final class GeckoRuntimeSettings implements Parcelable {
/* package */ int mScreenWidthOverride;
/* package */ int mScreenHeightOverride;
/* package */ Class<? extends Service> mCrashHandler;
/* package */ String mLocale;
private final Pref<?>[] mPrefs = new Pref<?>[] {
mCookieBehavior, mCookieLifetime, mConsoleOutput,
@ -402,9 +416,11 @@ public final class GeckoRuntimeSettings implements Parcelable {
mScreenWidthOverride = settings.mScreenWidthOverride;
mScreenHeightOverride = settings.mScreenHeightOverride;
mCrashHandler = settings.mCrashHandler;
mLocale = settings.mLocale;
}
/* package */ void flush() {
flushLocale();
for (final Pref<?> pref: mPrefs) {
pref.flush();
}
@ -545,6 +561,29 @@ public final class GeckoRuntimeSettings implements Parcelable {
return null;
}
/**
* Gets the locale code in Gecko format ("en" or "en-US").
*/
public String getLocale() {
return mLocale;
}
/**
* Set the locale.
*
* @param languageTag The locale code in Gecko format ("en-US").
*/
public void setLocale(String languageTag) {
mLocale = languageTag;
flushLocale();
}
private void flushLocale() {
final GeckoBundle data = new GeckoBundle(1);
data.putString("languageTag", mLocale);
EventDispatcher.getInstance().dispatch("GeckoView:SetLocale", data);
}
// Sync values with nsICookieService.idl.
@Retention(RetentionPolicy.SOURCE)
@IntDef({ COOKIE_ACCEPT_ALL, COOKIE_ACCEPT_FIRST_PARTY,
@ -753,6 +792,7 @@ public final class GeckoRuntimeSettings implements Parcelable {
out.writeInt(mScreenWidthOverride);
out.writeInt(mScreenHeightOverride);
out.writeString(mCrashHandler != null ? mCrashHandler.getName() : null);
out.writeString(mLocale);
}
// AIDL code may call readFromParcel even though it's not part of Parcelable.
@ -785,6 +825,8 @@ public final class GeckoRuntimeSettings implements Parcelable {
} catch (ClassNotFoundException e) {
}
}
mLocale = source.readString();
}
public static final Parcelable.Creator<GeckoRuntimeSettings> CREATOR

Просмотреть файл

@ -150,24 +150,13 @@ class GeckoViewNavigation extends GeckoViewModule {
return browser || null;
}
isURIHandled(aUri, aWhere, aFlags) {
debug `isURIHandled: uri=${aUri} where=${aWhere} flags=${aFlags}`;
let handled = undefined;
LoadURIDelegate.load(this.window, this.eventDispatcher, aUri, aWhere, aFlags).then((response) => {
handled = response;
});
Services.tm.spinEventLoopUntil(() => this.window.closed || handled !== undefined);
return handled;
}
// nsIBrowserDOMWindow.
createContentWindow(aUri, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
debug `createContentWindow: uri=${aUri && aUri.spec}
where=${aWhere} flags=${aFlags}`;
if (this.isURIHandled(aUri, aWhere, aFlags)) {
if (LoadURIDelegate.load(this.window, this.eventDispatcher,
aUri, aWhere, aFlags)) {
// The app has handled the load, abort open-window handling.
Components.returnCode = Cr.NS_ERROR_ABORT;
return null;
@ -190,7 +179,8 @@ class GeckoViewNavigation extends GeckoViewModule {
nextTabParentId=${aNextTabParentId}
name=${aName}`;
if (this.isURIHandled(aUri, aWhere, aFlags)) {
if (LoadURIDelegate.load(this.window, this.eventDispatcher,
aUri, aWhere, aFlags)) {
// The app has handled the load, abort open-window handling.
Components.returnCode = Cr.NS_ERROR_ABORT;
return null;
@ -210,7 +200,8 @@ class GeckoViewNavigation extends GeckoViewModule {
debug `handleOpenUri: uri=${aUri && aUri.spec}
where=${aWhere} flags=${aFlags}`;
if (this.isURIHandled(aUri, aWhere, aFlags)) {
if (LoadURIDelegate.load(this.window, this.eventDispatcher,
aUri, aWhere, aFlags)) {
return null;
}

Просмотреть файл

@ -20,7 +20,7 @@ const LoadURIDelegate = {
// Return whether the loading has been handled.
load: function(aWindow, aEventDispatcher, aUri, aWhere, aFlags) {
if (!aWindow) {
return Promise.resolve(false);
return false;
}
const message = {
@ -30,7 +30,18 @@ const LoadURIDelegate = {
flags: aFlags
};
return aEventDispatcher.sendRequestForResult(message).then((response) => response || false).catch(() => false);
let handled = undefined;
aEventDispatcher.sendRequestForResult(message).then(response => {
handled = response;
}, () => {
// There was an error or listener was not registered in GeckoSession,
// treat as unhandled.
handled = false;
});
Services.tm.spinEventLoopUntil(() =>
aWindow.closed || handled !== undefined);
return handled || false;
},
handleLoadError: function(aWindow, aEventDispatcher, aUri, aError,

Просмотреть файл

@ -52,13 +52,6 @@ interface nsIChannelEventSink : nsISupports
*/
const unsigned long REDIRECT_STS_UPGRADE = 1 << 3;
/**
* This redirect has already been presented to the nsILoadURIDelegate
* for possible handling; if this flag is set we may safely skip checking
* if the nsILoadURIDelegate will handle the redirect.
*/
const unsigned long REDIRECT_DELEGATES_CHECKED = 1 << 4;
/**
* Called when a redirect occurs. This may happen due to an HTTP 3xx status
* code. The purpose of this method is to notify the sink that a redirect

Просмотреть файл

@ -207,6 +207,7 @@ this.AntiTracking = {
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", cookieBehavior != BEHAVIOR_ACCEPT],
[win.ContentBlocking.prefIntroCount, win.ContentBlocking.MAX_INTROS],
["browser.fastblock.enabled", false], // prevent intermittent failures
]});
if (extraPrefs && Array.isArray(extraPrefs) && extraPrefs.length) {

Просмотреть файл

@ -6,8 +6,6 @@
#include "nspr.h"
#include "mozilla/Logging.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "nsDocLoader.h"
#include "nsCURILoader.h"
@ -36,8 +34,6 @@
#include "nsIDocument.h"
#include "nsPresContext.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsILoadURIDelegate.h"
#include "nsIBrowserDOMWindow.h"
using mozilla::DebugOnly;
using mozilla::LogLevel;
@ -1425,106 +1421,11 @@ int64_t nsDocLoader::CalculateMaxProgress()
return max;
}
class LoadURIDelegateRedirectHandler final : public mozilla::dom::PromiseNativeHandler
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(LoadURIDelegateRedirectHandler)
LoadURIDelegateRedirectHandler(nsDocLoader* aDocLoader,
nsIChannel* aOldChannel,
nsIChannel* aNewChannel,
uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* aCallback)
: mDocLoader(aDocLoader)
, mOldChannel(aOldChannel)
, mNewChannel(aNewChannel)
, mFlags(aFlags)
, mCallback(aCallback)
{}
void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
if (aValue.isBoolean() && aValue.toBoolean()) {
// The app handled the redirect, notify the callback
mCallback->OnRedirectVerifyCallback(NS_ERROR_ABORT);
} else {
UnhandledCallback();
}
}
void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
UnhandledCallback();
}
private:
~LoadURIDelegateRedirectHandler()
{}
void UnhandledCallback()
{
// If the redirect wasn't handled by the nsILoadURIDelegate, let Gecko
// handle it.
mFlags |= nsIChannelEventSink::REDIRECT_DELEGATES_CHECKED;
mDocLoader->AsyncOnChannelRedirect(mOldChannel, mNewChannel, mFlags,
mCallback);
}
RefPtr<nsDocLoader> mDocLoader;
nsCOMPtr<nsIChannel> mOldChannel;
nsCOMPtr<nsIChannel> mNewChannel;
uint32_t mFlags;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mCallback;
};
NS_IMPL_CYCLE_COLLECTION(LoadURIDelegateRedirectHandler, mDocLoader,
mOldChannel, mNewChannel, mCallback)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LoadURIDelegateRedirectHandler)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(LoadURIDelegateRedirectHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadURIDelegateRedirectHandler)
NS_IMETHODIMP nsDocLoader::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
uint32_t aFlags,
nsIAsyncVerifyRedirectCallback *cb)
{
if ((aFlags &
(nsIChannelEventSink::REDIRECT_TEMPORARY |
nsIChannelEventSink::REDIRECT_PERMANENT)) &&
!(aFlags & nsIChannelEventSink::REDIRECT_DELEGATES_CHECKED)) {
nsCOMPtr<nsIDocShell> docShell =
do_QueryInterface(static_cast<nsIRequestObserver*>(this));
nsCOMPtr<nsILoadURIDelegate> delegate;
docShell->GetLoadURIDelegate(getter_AddRefs(delegate));
nsCOMPtr<nsIURI> newURI;
aNewChannel->GetURI(getter_AddRefs(newURI));
if (newURI && delegate) {
RefPtr<mozilla::dom::Promise> promise;
const int where = nsIBrowserDOMWindow::OPEN_CURRENTWINDOW;
nsresult rv = delegate->LoadURI(newURI, where, /* flags */ 0,
/* triggering principal */ nullptr,
getter_AddRefs(promise));
if (NS_SUCCEEDED(rv) && promise) {
RefPtr<LoadURIDelegateRedirectHandler> handler =
new LoadURIDelegateRedirectHandler(this, aOldChannel, aNewChannel,
aFlags, cb);
promise->AppendNativeHandler(handler);
return NS_OK;
}
}
}
if (aOldChannel)
{
nsLoadFlags loadFlags = 0;

Просмотреть файл

@ -789,7 +789,8 @@ nsBaseDragService::DrawDragForImage(nsPresContext* aPresContext,
imgIContainer::FRAME_CURRENT,
SamplingFilter::GOOD, /* no SVGImageContext */ Nothing(),
imgIContainer::FLAG_SYNC_DECODE, 1.0);
if (res == ImgDrawResult::BAD_IMAGE || res == ImgDrawResult::BAD_ARGS) {
if (res == ImgDrawResult::BAD_IMAGE || res == ImgDrawResult::BAD_ARGS ||
res == ImgDrawResult::NOT_SUPPORTED) {
return NS_ERROR_FAILURE;
}
*aSurface = dt->Snapshot();

Просмотреть файл

@ -26,11 +26,10 @@ interface nsILoadURIDelegate : nsISupports
* @param aWhere See possible values described in nsIBrowserDOMWindow.
* @param aFlags Flags which control the behavior of the load.
* @param aTriggeringPrincipal The principal that triggered the load of aURI.
* @return A promise which can resolve to a boolean indicating whether or
* not the app handled the load. Rejection should be treated the same
* as a false resolution.
*
* Returns whether the load has been successfully handled.
*/
Promise
boolean
loadURI(in nsIURI aURI, in short aWhere, in long aFlags,
in nsIPrincipal aTriggeringPrincipal);