зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to m-c. a=merge
This commit is contained in:
Коммит
d6f23d6c08
|
@ -85,7 +85,7 @@ tasks:
|
|||
|
||||
# Note: This task is built server side without the context or tooling that
|
||||
# exist in tree so we must hard code the version
|
||||
image: 'taskcluster/decision:0.1.5'
|
||||
image: 'taskcluster/decision:0.1.6'
|
||||
|
||||
maxRunTime: 1800
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "cargo 0.13.0-nightly (664125b 2016-07-19)",
|
||||
"size": 3123796,
|
||||
"digest": "4b9d2bcb8488b6649ba6c748e19d33bfceb25c7566e882fc7e00322392e424a5a9c5878c11c61d57cdaecf67bcc110842c6eff95e49736e8f3c83d9ce1677122",
|
||||
"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
|
||||
"size": 3245716,
|
||||
"digest": "d5bb0d88ce7bb1b5a316d7a8ca6341672f5ee8008fa7754511bf53fabd54c0770e95397232896d6087547891f1143f6968d8b1e106e39800b43defeb0025c7c0",
|
||||
"algorithm": "sha512",
|
||||
"filename": "cargo.tar.xz",
|
||||
"unpack": true
|
||||
|
|
|
@ -845,7 +845,7 @@ BrowserGlue.prototype = {
|
|||
|
||||
if (samples >= Services.prefs.getIntPref("browser.slowStartup.maxSamples")) {
|
||||
if (averageTime > Services.prefs.getIntPref("browser.slowStartup.timeThreshold"))
|
||||
this._showSlowStartupNotification();
|
||||
this._calculateProfileAgeInDays().then(this._showSlowStartupNotification, null);
|
||||
averageTime = 0;
|
||||
samples = 0;
|
||||
}
|
||||
|
@ -854,7 +854,25 @@ BrowserGlue.prototype = {
|
|||
Services.prefs.setIntPref("browser.slowStartup.samples", samples);
|
||||
},
|
||||
|
||||
_showSlowStartupNotification: function () {
|
||||
_calculateProfileAgeInDays: Task.async(function* () {
|
||||
let ProfileAge = Cu.import("resource://gre/modules/ProfileAge.jsm", {}).ProfileAge;
|
||||
let profileAge = new ProfileAge(null, null);
|
||||
|
||||
let creationDate = yield profileAge.created;
|
||||
let resetDate = yield profileAge.reset;
|
||||
|
||||
// if the profile was reset, consider the
|
||||
// reset date for its age.
|
||||
let profileDate = resetDate || creationDate;
|
||||
|
||||
const ONE_DAY = 24 * 60 * 60 * 1000;
|
||||
return (Date.now() - profileDate) / ONE_DAY;
|
||||
}),
|
||||
|
||||
_showSlowStartupNotification: function (profileAge) {
|
||||
if (profileAge < 90) // 3 months
|
||||
return;
|
||||
|
||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
||||
if (!win)
|
||||
return;
|
||||
|
|
|
@ -127,7 +127,20 @@ var gSecurityPane = {
|
|||
*/
|
||||
showPasswordExceptions: function ()
|
||||
{
|
||||
gSubDialog.open("chrome://passwordmgr/content/passwordManagerExceptions.xul");
|
||||
var bundlePrefs = document.getElementById("bundlePreferences");
|
||||
var params = {
|
||||
blockVisible: true,
|
||||
sessionVisible: false,
|
||||
allowVisible: false,
|
||||
hideStatusColumn: true,
|
||||
prefilledHost: "",
|
||||
permissionType: "login-saving",
|
||||
windowTitle: bundlePrefs.getString("savedLoginsExceptions_title"),
|
||||
introText: bundlePrefs.getString("savedLoginsExceptions_desc")
|
||||
};
|
||||
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
null, params);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -306,7 +306,7 @@ var gPermissionManager = {
|
|||
this._handleCapabilityChange();
|
||||
}
|
||||
else if (aData == "deleted") {
|
||||
this._removePermissionFromList(permission);
|
||||
this._removePermissionFromList(permission.principal);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
- 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog SYSTEM "chrome://browser/locale/preferences/permissions.dtd" >
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
<separator class="thin"/>
|
||||
<label id="urlLabel" control="url" value="&address.label;" accesskey="&address.accesskey;"/>
|
||||
<hbox align="start">
|
||||
<textbox id="url" flex="1"
|
||||
<textbox id="url" flex="1"
|
||||
oninput="gPermissionManager.onHostInput(event.target);"
|
||||
onkeypress="gPermissionManager.onHostKeyPress(event);"/>
|
||||
</hbox>
|
||||
|
@ -69,7 +69,7 @@
|
|||
oncommand="gPermissionManager.onPermissionDeleted();"/>
|
||||
<button id="removeAllPermissions"
|
||||
icon="clear" label="&removeallpermissions.label;"
|
||||
accesskey="&removeallpermissions.accesskey;"
|
||||
accesskey="&removeallpermissions.accesskey;"
|
||||
oncommand="gPermissionManager.onAllPermissionsDeleted();"/>
|
||||
</hbox>
|
||||
<spacer flex="1"/>
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "cargo 0.13.0-nightly (664125b 2016-07-19)",
|
||||
"size": 3123796,
|
||||
"digest": "4b9d2bcb8488b6649ba6c748e19d33bfceb25c7566e882fc7e00322392e424a5a9c5878c11c61d57cdaecf67bcc110842c6eff95e49736e8f3c83d9ce1677122",
|
||||
"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
|
||||
"size": 3245716,
|
||||
"digest": "d5bb0d88ce7bb1b5a316d7a8ca6341672f5ee8008fa7754511bf53fabd54c0770e95397232896d6087547891f1143f6968d8b1e106e39800b43defeb0025c7c0",
|
||||
"algorithm": "sha512",
|
||||
"filename": "cargo.tar.xz",
|
||||
"unpack": true
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "cargo 0.13.0-nightly (664125b 2016-07-19)",
|
||||
"size": 3123796,
|
||||
"digest": "4b9d2bcb8488b6649ba6c748e19d33bfceb25c7566e882fc7e00322392e424a5a9c5878c11c61d57cdaecf67bcc110842c6eff95e49736e8f3c83d9ce1677122",
|
||||
"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
|
||||
"size": 3245716,
|
||||
"digest": "d5bb0d88ce7bb1b5a316d7a8ca6341672f5ee8008fa7754511bf53fabd54c0770e95397232896d6087547891f1143f6968d8b1e106e39800b43defeb0025c7c0",
|
||||
"algorithm": "sha512",
|
||||
"filename": "cargo.tar.xz",
|
||||
"unpack": true
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "cargo 0.13.0-nightly (664125b 2016-07-19)",
|
||||
"size": 2571167,
|
||||
"digest": "b2616459fbf15c75b54628a6bfe8cf89c0841ea08431f5096e72be4fac4c685785dfc7a2f18a03a5f7bd377e78d3c108e5029b12616842cbbd0497ff7363fdaf",
|
||||
"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
|
||||
"size": 2715131,
|
||||
"digest": "f037d2bbbeccb2c95519e083d6d9eecb5cb06a510e849b5721d6933a6c2428203b93ed3d20d3f20329f4d4eee17177d762f051b1ae79fee97d93b84611f3df66",
|
||||
"algorithm": "sha512",
|
||||
"filename": "cargo.tar.bz2",
|
||||
"unpack": true
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "cargo 0.13.0-nightly (664125b 2016-07-19)",
|
||||
"size": 2298848,
|
||||
"digest": "d3d1f7b6d195248550f98eb8ce87aa314d36a8a667c110ff2058777fe5a97b7007a41dc1c8a4605c4230e9105972768918222352d5e0fdebbc49639671de38ca",
|
||||
"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
|
||||
"size": 2402000,
|
||||
"digest": "56f12f7ac437742ed717ce0ccfb0b4134160948e45d73016e48d9033567e5b01a171ac95dd7965eb007702c31da73274b5913281655f461f611ddeee37181ecc",
|
||||
"algorithm": "sha512",
|
||||
"filename": "cargo.tar.bz2",
|
||||
"unpack": true
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "cargo 0.13.0-nightly (664125b 2016-07-19)",
|
||||
"size": 2561498,
|
||||
"digest": "d300fd06b16efe49bdb1a238d516c8797d2de0edca7efadd55249401e1dd1d775fb84649630e273f95d9e8b956d87d1f75726c0a68294d25fafe078c3b2b9ba9",
|
||||
"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
|
||||
"size": 2677831,
|
||||
"digest": "eada1edd6142dcde907f14f23c08a2a0b86f108a8fb242f62be6573bbbe1d3b2a4a04c05465d561253d6a617e18cdabee3c87d8cef9a1b5bdd20fe835ef25ff1",
|
||||
"algorithm": "sha512",
|
||||
"filename": "cargo.tar.bz2",
|
||||
"unpack": true
|
||||
|
|
|
@ -17,7 +17,8 @@ const TEST_THRESHOLD = {
|
|||
};
|
||||
|
||||
const ADDON_ROLLOUT_POLICY = {
|
||||
"beta" : "2a", // Set 2 + any WebExtension
|
||||
"beta" : "49a", // 10 tested add-ons + any WebExtension
|
||||
"release" : "49a", // 10 tested add-ons + any WebExtension
|
||||
};
|
||||
|
||||
const PREF_COHORT_SAMPLE = "e10s.rollout.cohortSample";
|
||||
|
|
|
@ -31,6 +31,8 @@ notificationspermissionstext4=Control which websites are always or never allowed
|
|||
notificationspermissionstitle=Notification Permissions
|
||||
invalidURI=Please enter a valid hostname
|
||||
invalidURITitle=Invalid Hostname Entered
|
||||
savedLoginsExceptions_title=Exceptions - Saved Logins
|
||||
savedLoginsExceptions_desc=Logins for the following sites will not be saved:
|
||||
|
||||
#### Block List Manager
|
||||
|
||||
|
@ -126,7 +128,7 @@ cookiesFiltered=The following cookies match your search:
|
|||
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# If you need to display the number of selected elements in your language,
|
||||
# you can use #1 in your localization as a placeholder for the number.
|
||||
# For example this is the English string with numbers:
|
||||
# For example this is the English string with numbers:
|
||||
# removeSelectedCookied=Remove #1 Selected;Remove #1 Selected
|
||||
removeSelectedCookies=Remove Selected;Remove Selected
|
||||
defaultUserContextLabel=None
|
||||
|
|
|
@ -147,6 +147,7 @@ skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keybo
|
|||
[browser_inspector_search-08.js]
|
||||
[browser_inspector_search-clear.js]
|
||||
[browser_inspector_search-filter_context-menu.js]
|
||||
subsuite = clipboard
|
||||
[browser_inspector_search_keyboard_trap.js]
|
||||
[browser_inspector_search-label.js]
|
||||
[browser_inspector_search-reserved.js]
|
||||
|
|
|
@ -45,6 +45,7 @@ skip-if = (toolkit == 'gonk' && !debug)
|
|||
[test_browserElement_oop_Close.html]
|
||||
[test_browserElement_oop_CookiesNotThirdParty.html]
|
||||
[test_browserElement_oop_CopyPaste.html]
|
||||
subsuite = clipboard
|
||||
[test_browserElement_oop_DOMRequestError.html]
|
||||
disabled = Disabling some OOP tests for WebIDL scope changes
|
||||
[test_browserElement_oop_DataURI.html]
|
||||
|
|
|
@ -758,6 +758,17 @@ VRDisplayOculus::SubmitFrame(TextureSourceD3D11* aSource,
|
|||
if (!mIsPresenting) {
|
||||
return;
|
||||
}
|
||||
if (mRenderTargets.IsEmpty()) {
|
||||
/**
|
||||
* XXX - We should resolve fail the promise returned by
|
||||
* VRDisplay.requestPresent() when the DX11 resources fail allocation
|
||||
* in VRDisplayOculus::StartPresentation().
|
||||
* Bailing out here prevents the crash but content should be aware
|
||||
* that frames are not being presented.
|
||||
* See Bug 1299309.
|
||||
**/
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mDevice);
|
||||
MOZ_ASSERT(mContext);
|
||||
|
||||
|
|
|
@ -3589,8 +3589,13 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
|
|||
basic->BeginTransaction();
|
||||
basic->SetTarget(context);
|
||||
|
||||
if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) {
|
||||
static_cast<nsDisplaySVGEffects*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
|
||||
if (aItem->GetType() == nsDisplayItem::TYPE_MASK) {
|
||||
static_cast<nsDisplayMask*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
|
||||
if (basic->InTransaction()) {
|
||||
basic->AbortTransaction();
|
||||
}
|
||||
} else if (aItem->GetType() == nsDisplayItem::TYPE_FILTER){
|
||||
static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
|
||||
if (basic->InTransaction()) {
|
||||
basic->AbortTransaction();
|
||||
}
|
||||
|
|
|
@ -51,7 +51,8 @@ DECLARE_DISPLAY_ITEM_TYPE(SCROLL_INFO_LAYER)
|
|||
DECLARE_DISPLAY_ITEM_TYPE(SELECTION_OVERLAY)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_EFFECTS)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(MASK)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(FILTER)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_GLYPHS)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_PATH_GEOMETRY)
|
||||
|
|
|
@ -1009,7 +1009,10 @@ nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
|
|||
}
|
||||
|
||||
nsPresContext* pc = aReferenceFrame->PresContext();
|
||||
pc->GetDocShell()->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
|
||||
nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
|
||||
if (docShell) {
|
||||
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
|
||||
}
|
||||
mIsInChromePresContext = pc->IsChrome();
|
||||
}
|
||||
|
||||
|
@ -1025,7 +1028,10 @@ nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame)
|
|||
|
||||
if (!mPresShellStates.IsEmpty()) {
|
||||
nsPresContext* pc = CurrentPresContext();
|
||||
pc->GetDocShell()->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
|
||||
nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
|
||||
if (docShell) {
|
||||
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
|
||||
}
|
||||
mIsInChromePresContext = pc->IsChrome();
|
||||
}
|
||||
}
|
||||
|
@ -6677,128 +6683,6 @@ nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx,
|
||||
LayerManager* aManager)
|
||||
{
|
||||
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(),
|
||||
mFrame, mVisibleRect,
|
||||
borderArea, aBuilder,
|
||||
aManager, mOpacityItemCreated);
|
||||
|
||||
image::DrawResult result =
|
||||
nsSVGIntegrationUtils::PaintFramesWithEffects(params);
|
||||
|
||||
nsDisplaySVGEffectsGeometry::UpdateDrawResult(this, result);
|
||||
}
|
||||
|
||||
LayerState
|
||||
nsDisplaySVGEffects::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
return LAYER_SVG_EFFECTS;
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters)
|
||||
{
|
||||
const nsIContent* content = mFrame->GetContent();
|
||||
bool hasSVGLayout = (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
if (hasSVGLayout) {
|
||||
nsISVGChildFrame *svgChildFrame = do_QueryFrame(mFrame);
|
||||
if (!svgChildFrame || !mFrame->GetContent()->IsSVGElement()) {
|
||||
NS_ASSERTION(false, "why?");
|
||||
return nullptr;
|
||||
}
|
||||
if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
|
||||
return nullptr; // The SVG spec says not to draw filters for this
|
||||
}
|
||||
}
|
||||
|
||||
if (mFrame->StyleEffects()->mOpacity == 0.0f &&
|
||||
!mOpacityItemCreated)
|
||||
return nullptr;
|
||||
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
|
||||
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
|
||||
effectProperties.GetClipPathFrame(&isOK);
|
||||
|
||||
if (!isOK) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ContainerLayerParameters newContainerParameters = aContainerParameters;
|
||||
if (effectProperties.HasValidFilter()) {
|
||||
newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
|
||||
}
|
||||
|
||||
RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
||||
newContainerParameters, nullptr);
|
||||
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsDisplaySVGEffects::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
|
||||
if (effectProperties.HasValidFilter()) {
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
return nsDisplayWrapList::GetComponentAlphaBounds(aBuilder);
|
||||
}
|
||||
|
||||
bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) {
|
||||
nsPoint offset = ToReferenceFrame();
|
||||
nsRect dirtyRect =
|
||||
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame,
|
||||
mVisibleRect - offset) +
|
||||
offset;
|
||||
|
||||
// Our children may be made translucent or arbitrarily deformed so we should
|
||||
// not allow them to subtract area from aVisibleRegion.
|
||||
nsRegion childrenVisible(dirtyRect);
|
||||
nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder));
|
||||
mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nsDisplaySVGEffects::TryMerge(nsDisplayItem* aItem)
|
||||
{
|
||||
if (aItem->GetType() != TYPE_SVG_EFFECTS)
|
||||
return false;
|
||||
// items for the same content element should be merged into a single
|
||||
// compositing group
|
||||
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
|
||||
if (aItem->Frame()->GetContent() != mFrame->GetContent())
|
||||
return false;
|
||||
if (aItem->GetClip() != GetClip())
|
||||
return false;
|
||||
if (aItem->ScrollClip() != ScrollClip())
|
||||
return false;
|
||||
nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem);
|
||||
MergeFromTrackingMergedFrames(other);
|
||||
mEffectsBounds.UnionRect(mEffectsBounds,
|
||||
other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
|
||||
return true;
|
||||
}
|
||||
|
||||
gfxRect
|
||||
nsDisplaySVGEffects::BBoxInUserSpace() const
|
||||
{
|
||||
|
@ -6838,9 +6722,130 @@ nsDisplaySVGEffects::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
}
|
||||
|
||||
bool nsDisplaySVGEffects::ValidateSVGFrame()
|
||||
{
|
||||
const nsIContent* content = mFrame->GetContent();
|
||||
bool hasSVGLayout = (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
if (hasSVGLayout) {
|
||||
nsISVGChildFrame *svgChildFrame = do_QueryFrame(mFrame);
|
||||
if (!svgChildFrame || !mFrame->GetContent()->IsSVGElement()) {
|
||||
NS_ASSERTION(false, "why?");
|
||||
return false;
|
||||
}
|
||||
if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
|
||||
return false; // The SVG spec says not to draw filters for this
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsDisplayMask::nsDisplayMask(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList,
|
||||
bool aOpacityItemCreated)
|
||||
: nsDisplaySVGEffects(aBuilder, aFrame, aList, aOpacityItemCreated)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplayMask);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsDisplayMask::~nsDisplayMask()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsDisplayMask);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool nsDisplayMask::TryMerge(nsDisplayItem* aItem)
|
||||
{
|
||||
if (aItem->GetType() != TYPE_MASK)
|
||||
return false;
|
||||
|
||||
// items for the same content element should be merged into a single
|
||||
// compositing group
|
||||
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
|
||||
if (aItem->Frame()->GetContent() != mFrame->GetContent())
|
||||
return false;
|
||||
if (aItem->GetClip() != GetClip())
|
||||
return false;
|
||||
if (aItem->ScrollClip() != ScrollClip())
|
||||
return false;
|
||||
nsDisplayMask* other = static_cast<nsDisplayMask*>(aItem);
|
||||
MergeFromTrackingMergedFrames(other);
|
||||
mEffectsBounds.UnionRect(mEffectsBounds,
|
||||
other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayMask::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters)
|
||||
{
|
||||
if (!ValidateSVGFrame()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mFrame->StyleEffects()->mOpacity == 0.0f && !mOpacityItemCreated) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
|
||||
bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
|
||||
effectProperties.GetClipPathFrame(&isOK);
|
||||
|
||||
if (!isOK) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
||||
aContainerParameters, nullptr);
|
||||
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
LayerState
|
||||
nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
return LAYER_SVG_EFFECTS;
|
||||
}
|
||||
|
||||
bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) {
|
||||
// Our children may be made translucent or arbitrarily deformed so we should
|
||||
// not allow them to subtract area from aVisibleRegion.
|
||||
nsRegion childrenVisible(mVisibleRect);
|
||||
nsRect r = mVisibleRect.Intersect(mList.GetBounds(aBuilder));
|
||||
mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayMask::PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx,
|
||||
LayerManager* aManager)
|
||||
{
|
||||
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(),
|
||||
mFrame, mVisibleRect,
|
||||
borderArea, aBuilder,
|
||||
aManager, mOpacityItemCreated);
|
||||
|
||||
image::DrawResult result =
|
||||
nsSVGIntegrationUtils::PaintMaskAndClipPath(params);
|
||||
|
||||
nsDisplaySVGEffectsGeometry::UpdateDrawResult(this, result);
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
void
|
||||
nsDisplaySVGEffects::PrintEffects(nsACString& aTo)
|
||||
nsDisplayMask::PrintEffects(nsACString& aTo)
|
||||
{
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
||||
|
@ -6869,13 +6874,7 @@ nsDisplaySVGEffects::PrintEffects(nsACString& aTo)
|
|||
aTo += "clip(basic-shape)";
|
||||
first = false;
|
||||
}
|
||||
if (effectProperties.HasValidFilter()) {
|
||||
if (!first) {
|
||||
aTo += ", ";
|
||||
}
|
||||
aTo += "filter";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (effectProperties.GetFirstMaskFrame()) {
|
||||
if (!first) {
|
||||
aTo += ", ";
|
||||
|
@ -6886,3 +6885,140 @@ nsDisplaySVGEffects::PrintEffects(nsACString& aTo)
|
|||
}
|
||||
#endif
|
||||
|
||||
nsDisplayFilter::nsDisplayFilter(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList,
|
||||
bool aOpacityItemCreated)
|
||||
: nsDisplaySVGEffects(aBuilder, aFrame, aList, aOpacityItemCreated)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplayFilter);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsDisplayFilter::~nsDisplayFilter()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsDisplayFilter);
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayFilter::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters)
|
||||
{
|
||||
if (!ValidateSVGFrame()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mFrame->StyleEffects()->mOpacity == 0.0f && !mOpacityItemCreated) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
|
||||
ContainerLayerParameters newContainerParameters = aContainerParameters;
|
||||
if (effectProperties.HasValidFilter()) {
|
||||
newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
|
||||
}
|
||||
|
||||
RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
||||
newContainerParameters, nullptr);
|
||||
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
bool nsDisplayFilter::TryMerge(nsDisplayItem* aItem)
|
||||
{
|
||||
if (aItem->GetType() != TYPE_FILTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// items for the same content element should be merged into a single
|
||||
// compositing group.
|
||||
// aItem->Frame() returns non-null because it's nsDisplayFilter
|
||||
if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
|
||||
return false;
|
||||
}
|
||||
if (aItem->GetClip() != GetClip()) {
|
||||
return false;
|
||||
}
|
||||
if (aItem->ScrollClip() != ScrollClip()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDisplayFilter* other = static_cast<nsDisplayFilter*>(aItem);
|
||||
MergeFromTrackingMergedFrames(other);
|
||||
mEffectsBounds.UnionRect(mEffectsBounds,
|
||||
other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LayerState
|
||||
nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
return LAYER_SVG_EFFECTS;
|
||||
}
|
||||
|
||||
bool nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) {
|
||||
nsPoint offset = ToReferenceFrame();
|
||||
nsRect dirtyRect =
|
||||
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame,
|
||||
mVisibleRect - offset) +
|
||||
offset;
|
||||
|
||||
// Our children may be made translucent or arbitrarily deformed so we should
|
||||
// not allow them to subtract area from aVisibleRegion.
|
||||
nsRegion childrenVisible(dirtyRect);
|
||||
nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder));
|
||||
mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayFilter::PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx,
|
||||
LayerManager* aManager)
|
||||
{
|
||||
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(),
|
||||
mFrame, mVisibleRect,
|
||||
borderArea, aBuilder,
|
||||
aManager, mOpacityItemCreated);
|
||||
|
||||
image::DrawResult result =
|
||||
nsSVGIntegrationUtils::PaintFilter(params);
|
||||
|
||||
nsDisplaySVGEffectsGeometry::UpdateDrawResult(this, result);
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
void
|
||||
nsDisplayFilter::PrintEffects(nsACString& aTo)
|
||||
{
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
bool first = true;
|
||||
aTo += " effects=(";
|
||||
if (mFrame->StyleEffects()->mOpacity != 1.0f) {
|
||||
first = false;
|
||||
aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
|
||||
}
|
||||
if (effectProperties.HasValidFilter()) {
|
||||
if (!first) {
|
||||
aTo += ", ";
|
||||
}
|
||||
aTo += "filter";
|
||||
first = false;
|
||||
}
|
||||
aTo += ")";
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3782,18 +3782,14 @@ private:
|
|||
int32_t mAPD, mParentAPD;
|
||||
};
|
||||
|
||||
/**
|
||||
* A display item to paint a stacking context with effects
|
||||
* set by the stacking context root frame's style.
|
||||
*/
|
||||
class nsDisplaySVGEffects : public nsDisplayWrapList {
|
||||
class nsDisplaySVGEffects: public nsDisplayWrapList {
|
||||
public:
|
||||
nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsDisplayList* aList, bool aOpacityItemCreated);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplaySVGEffects();
|
||||
#endif
|
||||
|
||||
|
||||
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap) override;
|
||||
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
||||
|
@ -3804,22 +3800,10 @@ public:
|
|||
*aSnap = false;
|
||||
return mEffectsBounds + ToReferenceFrame();
|
||||
}
|
||||
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override;
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) override;
|
||||
virtual bool TryMerge(nsDisplayItem* aItem) override;
|
||||
|
||||
virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
|
||||
return false;
|
||||
}
|
||||
NS_DISPLAY_DECL_NAME("SVGEffects", TYPE_SVG_EFFECTS)
|
||||
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters) override;
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) override;
|
||||
|
||||
gfxRect BBoxInUserSpace() const;
|
||||
gfxPoint UserSpaceOffset() const;
|
||||
|
@ -3831,16 +3815,9 @@ public:
|
|||
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion* aInvalidRegion) override;
|
||||
protected:
|
||||
bool ValidateSVGFrame();
|
||||
|
||||
void PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx,
|
||||
LayerManager* aManager);
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
void PrintEffects(nsACString& aTo);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// relative to mFrame
|
||||
nsRect mEffectsBounds;
|
||||
// True if the caller also created an nsDisplayOpacity item, and we should tell
|
||||
|
@ -3848,6 +3825,68 @@ private:
|
|||
bool mOpacityItemCreated;
|
||||
};
|
||||
|
||||
/**
|
||||
* A display item to paint a stacking context with mask and clip effects
|
||||
* set by the stacking context root frame's style.
|
||||
*/
|
||||
class nsDisplayMask : public nsDisplaySVGEffects {
|
||||
public:
|
||||
nsDisplayMask(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsDisplayList* aList, bool aOpacityItemCreated);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayMask();
|
||||
#endif
|
||||
|
||||
NS_DISPLAY_DECL_NAME("Mask", TYPE_MASK)
|
||||
|
||||
virtual bool TryMerge(nsDisplayItem* aItem) override;
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) override;
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters) override;
|
||||
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) override;
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
void PrintEffects(nsACString& aTo);
|
||||
#endif
|
||||
|
||||
void PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx,
|
||||
LayerManager* aManager);
|
||||
};
|
||||
|
||||
class nsDisplayFilter : public nsDisplaySVGEffects {
|
||||
public:
|
||||
nsDisplayFilter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsDisplayList* aList, bool aOpacityItemCreated);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayFilter();
|
||||
#endif
|
||||
|
||||
NS_DISPLAY_DECL_NAME("Filter", TYPE_FILTER)
|
||||
|
||||
virtual bool TryMerge(nsDisplayItem* aItem) override;
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) override;
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters) override;
|
||||
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) override;
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
void PrintEffects(nsACString& aTo);
|
||||
#endif
|
||||
|
||||
void PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx,
|
||||
LayerManager* aManager);
|
||||
};
|
||||
|
||||
/* A display item that applies a transformation to all of its descendant
|
||||
* elements. This wrapper should only be used if there is a transform applied
|
||||
* to the root element.
|
||||
|
|
|
@ -196,9 +196,15 @@ PrintDisplayItemTo(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem,
|
|||
}
|
||||
}
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) {
|
||||
if (aItem->GetType() == nsDisplayItem::TYPE_MASK) {
|
||||
nsCString str;
|
||||
(static_cast<nsDisplaySVGEffects*>(aItem))->PrintEffects(str);
|
||||
(static_cast<nsDisplayMask*>(aItem))->PrintEffects(str);
|
||||
aStream << str.get();
|
||||
}
|
||||
|
||||
if (aItem->GetType() == nsDisplayItem::TYPE_FILTER) {
|
||||
nsCString str;
|
||||
(static_cast<nsDisplayFilter*>(aItem))->PrintEffects(str);
|
||||
aStream << str.get();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "nsBackdropFrame.h"
|
||||
|
||||
#include "nsDisplayList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsBackdropFrame)
|
||||
|
|
|
@ -29,14 +29,15 @@ public:
|
|||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
virtual LogicalSize ComputeAutoSize(nsRenderingContext *aRenderingContext,
|
||||
WritingMode aWM,
|
||||
const LogicalSize& aCBSize,
|
||||
nscoord aAvailableISize,
|
||||
const LogicalSize& aMargin,
|
||||
const LogicalSize& aBorder,
|
||||
const LogicalSize& aPadding,
|
||||
bool aShrinkWrap) override;
|
||||
virtual mozilla::LogicalSize
|
||||
ComputeAutoSize(nsRenderingContext *aRenderingContext,
|
||||
mozilla::WritingMode aWM,
|
||||
const mozilla::LogicalSize& aCBSize,
|
||||
nscoord aAvailableISize,
|
||||
const mozilla::LogicalSize& aMargin,
|
||||
const mozilla::LogicalSize& aBorder,
|
||||
const mozilla::LogicalSize& aPadding,
|
||||
bool aShrinkWrap) override;
|
||||
virtual void Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
|
|
|
@ -2441,16 +2441,30 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||
* output even if the element being filtered wouldn't otherwise do so.
|
||||
*/
|
||||
if (usingSVGEffects) {
|
||||
MOZ_ASSERT(StyleEffects()->HasFilters() ||
|
||||
nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this));
|
||||
|
||||
if (clipCapturedBy == ContainerItemType::eSVGEffects) {
|
||||
clipState.ExitStackingContextContents(&containerItemScrollClip);
|
||||
}
|
||||
// Revert to the post-filter dirty rect.
|
||||
buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects);
|
||||
/* List now emptied, so add the new list to the top. */
|
||||
resultList.AppendNewToTop(
|
||||
new (aBuilder) nsDisplaySVGEffects(aBuilder, this, &resultList, useOpacity));
|
||||
|
||||
// Skip all filter effects while generating glyph mask.
|
||||
if (StyleEffects()->HasFilters() && !aBuilder->IsForGenerateGlyphMask()) {
|
||||
/* List now emptied, so add the new list to the top. */
|
||||
resultList.AppendNewToTop(
|
||||
new (aBuilder) nsDisplayFilter(aBuilder, this, &resultList, useOpacity));
|
||||
}
|
||||
|
||||
if (nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this)) {
|
||||
/* List now emptied, so add the new list to the top. */
|
||||
resultList.AppendNewToTop(
|
||||
new (aBuilder) nsDisplayMask(aBuilder, this, &resultList, useOpacity));
|
||||
}
|
||||
|
||||
// Also add the hoisted scroll info items. We need those for APZ scrolling
|
||||
// because nsDisplaySVGEffects items can't build active layers.
|
||||
// because nsDisplayMask items can't build active layers.
|
||||
aBuilder->ExitSVGEffectsContents();
|
||||
resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
#include "nsGfxScrollFrame.h"
|
||||
|
||||
#include "ActiveLayerTracker.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "DisplayItemClip.h"
|
||||
#include "DisplayItemScrollClip.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsView.h"
|
||||
#include "nsIScrollable.h"
|
||||
|
@ -76,6 +78,7 @@
|
|||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::layout;
|
||||
|
||||
static uint32_t
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef _nsIStatefulFrame_h
|
||||
#define _nsIStatefulFrame_h
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsQueryFrame.h"
|
||||
|
||||
class nsPresState;
|
||||
|
|
|
@ -160,6 +160,15 @@ nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
|
|||
style->mMask.HasLayerWithImage();
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(const nsIFrame* aFrame)
|
||||
{
|
||||
const nsStyleSVGReset *style = aFrame->StyleSVGReset();
|
||||
return style->HasClipPath() ||
|
||||
style->mMask.HasLayerWithImage() ||
|
||||
(aFrame->StyleEffects()->mOpacity != 1.0f);
|
||||
}
|
||||
|
||||
// For non-SVG frames, this gives the offset to the frame's "user space".
|
||||
// For SVG frames, this returns a zero offset.
|
||||
static nsPoint
|
||||
|
@ -410,6 +419,22 @@ private:
|
|||
nsPoint mOffset;
|
||||
};
|
||||
|
||||
static IntRect
|
||||
ComputeClipExtsInDeviceSpace(gfxContext& aCtx)
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore matRestore(&aCtx);
|
||||
|
||||
// Get the clip extents in device space.
|
||||
aCtx.SetMatrix(gfxMatrix());
|
||||
gfxRect clippedFrameSurfaceRect = aCtx.GetClipExtents();
|
||||
clippedFrameSurfaceRect.RoundOut();
|
||||
|
||||
IntRect result;
|
||||
ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
|
||||
return mozilla::gfx::Factory::CheckSurfaceSize(result.Size()) ? result
|
||||
: IntRect();
|
||||
}
|
||||
|
||||
static IntRect
|
||||
ComputeMaskGeometry(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
const nsStyleSVGReset *svgReset,
|
||||
|
@ -463,17 +488,10 @@ ComputeMaskGeometry(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
|||
ctx.Clip(maskInUserSpace);
|
||||
}
|
||||
|
||||
// Get the clip extents in device space.
|
||||
ctx.SetMatrix(gfxMatrix());
|
||||
gfxRect clippedFrameSurfaceRect = ctx.GetClipExtents();
|
||||
clippedFrameSurfaceRect.RoundOut();
|
||||
|
||||
IntRect result = ComputeClipExtsInDeviceSpace(ctx);
|
||||
ctx.Restore();
|
||||
|
||||
IntRect result;
|
||||
ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
|
||||
return mozilla::gfx::Factory::CheckSurfaceSize(result.Size()) ? result
|
||||
: IntRect();
|
||||
return result;
|
||||
}
|
||||
|
||||
static DrawResult
|
||||
|
@ -595,8 +613,28 @@ GenerateMaskSurface(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
|||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
|
||||
static float
|
||||
ComputeOpacity(const nsSVGIntegrationUtils::PaintFramesParams& aParams)
|
||||
{
|
||||
nsIFrame* frame = aParams.frame;
|
||||
|
||||
MOZ_ASSERT(!nsSVGUtils::CanOptimizeOpacity(frame) ||
|
||||
!aParams.callerPaintsOpacity,
|
||||
"How can we be optimizing the opacity into the svg as well as having the caller paint it?");
|
||||
|
||||
float opacity = frame->StyleEffects()->mOpacity;
|
||||
|
||||
if (opacity != 1.0f &&
|
||||
(nsSVGUtils::CanOptimizeOpacity(frame) || aParams.callerPaintsOpacity)) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return opacity;
|
||||
}
|
||||
|
||||
static bool
|
||||
ValidateSVGFrame(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
bool aHasSVGLayout, DrawResult* aResult)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(!(aParams.frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
|
||||
|
@ -605,13 +643,128 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
|
|||
"Should not use nsSVGIntegrationUtils on this SVG frame");
|
||||
#endif
|
||||
|
||||
nsIFrame* frame = aParams.frame;
|
||||
const nsIContent* content = frame->GetContent();
|
||||
if (aHasSVGLayout) {
|
||||
nsISVGChildFrame *svgChildFrame = do_QueryFrame(frame);
|
||||
if (!svgChildFrame || !frame->GetContent()->IsSVGElement()) {
|
||||
NS_ASSERTION(false, "why?");
|
||||
*aResult = DrawResult::BAD_ARGS;
|
||||
return false;
|
||||
}
|
||||
if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
|
||||
// The SVG spec says not to draw _anything_
|
||||
*aResult = DrawResult::SUCCESS;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
SetupContextMatrix(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
nsPoint& aOffsetToBoundingBox,
|
||||
nsPoint& aToUserSpace,
|
||||
nsPoint& aOffsetToUserSpace)
|
||||
{
|
||||
nsIFrame* frame = aParams.frame;
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
|
||||
|
||||
nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame);
|
||||
aOffsetToBoundingBox = aParams.builder->ToReferenceFrame(firstFrame) - firstFrameOffset;
|
||||
if (!firstFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
/* Snap the offset if the reference frame is not a SVG frame,
|
||||
* since other frames will be snapped to pixel when rendering. */
|
||||
aOffsetToBoundingBox = nsPoint(
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.x),
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.y));
|
||||
}
|
||||
|
||||
// After applying only "aOffsetToBoundingBox", aCtx would have its origin at
|
||||
// the top left corner of frame's bounding box (over all continuations).
|
||||
// However, SVG painting needs the origin to be located at the origin of the
|
||||
// SVG frame's "user space", i.e. the space in which, for example, the
|
||||
// frame's BBox lives.
|
||||
// SVG geometry frames and foreignObject frames apply their own offsets, so
|
||||
// their position is relative to their user space. So for these frame types,
|
||||
// if we want aCtx to be in user space, we first need to subtract the
|
||||
// frame's position so that SVG painting can later add it again and the
|
||||
// frame is painted in the right place.
|
||||
|
||||
gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(frame);
|
||||
aToUserSpace =
|
||||
nsPoint(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
|
||||
nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
|
||||
|
||||
aOffsetToUserSpace = aOffsetToBoundingBox - aToUserSpace;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool hasSVGLayout = (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
NS_ASSERTION(hasSVGLayout || aOffsetToBoundingBox == aOffsetToUserSpace,
|
||||
"For non-SVG frames there shouldn't be any additional offset");
|
||||
#endif
|
||||
|
||||
gfxPoint devPixelOffsetToUserSpace =
|
||||
nsLayoutUtils::PointToGfxPoint(aOffsetToUserSpace,
|
||||
frame->PresContext()->AppUnitsPerDevPixel());
|
||||
aParams.ctx.SetMatrix(aParams.ctx.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
|
||||
}
|
||||
|
||||
static already_AddRefed<gfxContext>
|
||||
CreateBlendTarget(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
IntPoint& aTargetOffset)
|
||||
{
|
||||
MOZ_ASSERT(aParams.frame->StyleEffects()->mMixBlendMode !=
|
||||
NS_STYLE_BLEND_NORMAL);
|
||||
|
||||
// Create a temporary context to draw to so we can blend it back with
|
||||
// another operator.
|
||||
IntRect drawRect = ComputeClipExtsInDeviceSpace(aParams.ctx);
|
||||
|
||||
RefPtr<DrawTarget> targetDT = aParams.ctx.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::B8G8R8A8);
|
||||
if (!targetDT || !targetDT->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<gfxContext> target = gfxContext::CreateOrNull(targetDT);
|
||||
MOZ_ASSERT(target); // already checked the draw target above
|
||||
target->SetMatrix(aParams.ctx.CurrentMatrix() *
|
||||
gfxMatrix::Translation(-drawRect.TopLeft()));
|
||||
aTargetOffset = drawRect.TopLeft();
|
||||
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
BlendToTarget(const nsSVGIntegrationUtils::PaintFramesParams& aParams,
|
||||
gfxContext* aTarget, const IntPoint& aTargetOffset)
|
||||
{
|
||||
MOZ_ASSERT(aParams.frame->StyleEffects()->mMixBlendMode !=
|
||||
NS_STYLE_BLEND_NORMAL);
|
||||
|
||||
RefPtr<DrawTarget> targetDT = aTarget->GetDrawTarget();
|
||||
RefPtr<SourceSurface> targetSurf = targetDT->Snapshot();
|
||||
|
||||
gfxContext& context = aParams.ctx;
|
||||
gfxContextAutoSaveRestore save(&context);
|
||||
context.SetMatrix(gfxMatrix()); // This will be restored right after.
|
||||
RefPtr<gfxPattern> pattern = new gfxPattern(targetSurf, Matrix::Translation(aTargetOffset.x, aTargetOffset.y));
|
||||
context.SetPattern(pattern);
|
||||
context.Paint();
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
||||
{
|
||||
/* SVG defines the following rendering model:
|
||||
*
|
||||
* 1. Render geometry
|
||||
* 2. Apply filter
|
||||
* 3. Apply clipping, masking, group opacity
|
||||
*
|
||||
* We follow this, but perform a couple of optimizations:
|
||||
* We handle #3 here and perform a couple of optimizations:
|
||||
*
|
||||
* + Use cairo's clipPath when representable natively (single object
|
||||
* clip region).
|
||||
|
@ -619,30 +772,24 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
|
|||
* + Merge opacity and masking if both used together.
|
||||
*/
|
||||
nsIFrame* frame = aParams.frame;
|
||||
const nsIContent* content = frame->GetContent();
|
||||
DrawResult result = DrawResult::SUCCESS;
|
||||
bool hasSVGLayout = (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
if (hasSVGLayout) {
|
||||
nsISVGChildFrame *svgChildFrame = do_QueryFrame(frame);
|
||||
if (!svgChildFrame || !frame->GetContent()->IsSVGElement()) {
|
||||
NS_ASSERTION(false, "why?");
|
||||
return DrawResult::BAD_ARGS;
|
||||
}
|
||||
if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
|
||||
return DrawResult::SUCCESS; // The SVG spec says not to draw _anything_
|
||||
}
|
||||
if (!ValidateSVGFrame(aParams, hasSVGLayout, &result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
float opacity = frame->StyleEffects()->mOpacity;
|
||||
if (opacity != 1.0f &&
|
||||
(nsSVGUtils::CanOptimizeOpacity(frame) ||
|
||||
aParams.callerPaintsOpacity)) {
|
||||
opacity = 1.0f;
|
||||
}
|
||||
float opacity = ComputeOpacity(aParams);
|
||||
if (opacity == 0.0f) {
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
MOZ_ASSERT(!nsSVGUtils::CanOptimizeOpacity(frame) || !aParams.callerPaintsOpacity,
|
||||
"How can we be optimizing the opacity into the svg as well as having the caller paint it?");
|
||||
|
||||
gfxContext& context = aParams.ctx;
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint toUserSpace;
|
||||
nsPoint offsetToUserSpace;
|
||||
SetupContextMatrix(aParams, offsetToBoundingBox, toUserSpace,
|
||||
offsetToUserSpace);
|
||||
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
|
@ -655,46 +802,8 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
|
|||
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
|
||||
|
||||
bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
|
||||
gfxContext& context = aParams.ctx;
|
||||
DrawTarget* drawTarget = context.GetDrawTarget();
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
|
||||
|
||||
nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame);
|
||||
nsPoint offsetToBoundingBox = aParams.builder->ToReferenceFrame(firstFrame) - firstFrameOffset;
|
||||
if (!firstFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
/* Snap the offset if the reference frame is not a SVG frame,
|
||||
* since other frames will be snapped to pixel when rendering. */
|
||||
offsetToBoundingBox = nsPoint(
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
|
||||
}
|
||||
|
||||
// After applying only "offsetToBoundingBox", aCtx would have its origin at
|
||||
// the top left corner of frame's bounding box (over all continuations).
|
||||
// However, SVG painting needs the origin to be located at the origin of the
|
||||
// SVG frame's "user space", i.e. the space in which, for example, the
|
||||
// frame's BBox lives.
|
||||
// SVG geometry frames and foreignObject frames apply their own offsets, so
|
||||
// their position is relative to their user space. So for these frame types,
|
||||
// if we want aCtx to be in user space, we first need to subtract the
|
||||
// frame's position so that SVG painting can later add it again and the
|
||||
// frame is painted in the right place.
|
||||
|
||||
gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(frame);
|
||||
nsPoint toUserSpace(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
|
||||
nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
|
||||
nsPoint offsetToUserSpace = offsetToBoundingBox - toUserSpace;
|
||||
|
||||
NS_ASSERTION(hasSVGLayout || offsetToBoundingBox == offsetToUserSpace,
|
||||
"For non-SVG frames there shouldn't be any additional offset");
|
||||
|
||||
gfxPoint devPixelOffsetToUserSpace =
|
||||
nsLayoutUtils::PointToGfxPoint(offsetToUserSpace,
|
||||
frame->PresContext()->AppUnitsPerDevPixel());
|
||||
context.SetMatrix(context.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
|
||||
|
||||
gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame);
|
||||
|
||||
const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
|
||||
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
|
||||
|
||||
|
@ -718,25 +827,34 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
|
|||
bool shouldGenerateMaskLayer = maskFrames.Length() == 1 && maskFrames[0];
|
||||
#endif
|
||||
|
||||
// These are used if we require a temporary surface for a custom blend mode.
|
||||
RefPtr<gfxContext> target = &aParams.ctx;
|
||||
IntPoint targetOffset;
|
||||
bool shouldGenerateClipMaskLayer = clipPathFrame && !isTrivialClip;
|
||||
bool shouldApplyClipPath = clipPathFrame && isTrivialClip;
|
||||
bool shouldApplyBasicShape = !clipPathFrame && svgReset->HasClipPath();
|
||||
MOZ_ASSERT_IF(shouldGenerateClipMaskLayer,
|
||||
!shouldApplyClipPath && !shouldApplyBasicShape);
|
||||
|
||||
// These are used if we require a temporary surface for a custom blend mode.
|
||||
IntPoint targetOffset;
|
||||
RefPtr<gfxContext> target =
|
||||
(aParams.frame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
|
||||
? RefPtr<gfxContext>(&aParams.ctx).forget()
|
||||
: CreateBlendTarget(aParams, targetOffset);
|
||||
if (!target) {
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
|
||||
bool shouldGenerateMask = (opacity != 1.0f || shouldGenerateClipMaskLayer ||
|
||||
shouldGenerateMaskLayer);
|
||||
|
||||
bool complexEffects = false;
|
||||
DrawResult result = DrawResult::SUCCESS;
|
||||
/* Check if we need to do additional operations on this child's
|
||||
* rendering, which necessitates rendering into another surface. */
|
||||
if (opacity != 1.0f || (clipPathFrame && !isTrivialClip)
|
||||
|| frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL
|
||||
|| shouldGenerateMaskLayer) {
|
||||
complexEffects = true;
|
||||
|
||||
if (shouldGenerateMask) {
|
||||
context.Save();
|
||||
nsRect clipRect =
|
||||
frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
|
||||
context.Clip(NSRectToSnappedRect(clipRect,
|
||||
frame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*drawTarget));
|
||||
*context.GetDrawTarget()));
|
||||
Matrix maskTransform;
|
||||
RefPtr<SourceSurface> maskSurface;
|
||||
if (shouldGenerateMaskLayer) {
|
||||
|
@ -752,31 +870,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
|
|||
return result;
|
||||
}
|
||||
|
||||
if (frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
// Create a temporary context to draw to so we can blend it back with
|
||||
// another operator.
|
||||
gfxRect clipRect;
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore matRestore(&context);
|
||||
|
||||
context.SetMatrix(gfxMatrix());
|
||||
clipRect = context.GetClipExtents();
|
||||
}
|
||||
|
||||
IntRect drawRect = RoundedOut(ToRect(clipRect));
|
||||
|
||||
RefPtr<DrawTarget> targetDT = context.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::B8G8R8A8);
|
||||
if (!targetDT || !targetDT->IsValid()) {
|
||||
context.Restore();
|
||||
return result;
|
||||
}
|
||||
target = gfxContext::CreateOrNull(targetDT);
|
||||
MOZ_ASSERT(target); // already checked the draw target above
|
||||
target->SetMatrix(context.CurrentMatrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
|
||||
targetOffset = drawRect.TopLeft();
|
||||
}
|
||||
|
||||
if (clipPathFrame && !isTrivialClip) {
|
||||
if (shouldGenerateClipMaskLayer) {
|
||||
Matrix clippedMaskTransform;
|
||||
RefPtr<SourceSurface> clipMaskSurface =
|
||||
clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
|
||||
|
@ -789,69 +883,105 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
|
|||
}
|
||||
}
|
||||
|
||||
if (opacity != 1.0f || shouldGenerateMaskLayer ||
|
||||
(clipPathFrame && !isTrivialClip)) {
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity, maskSurface, maskTransform);
|
||||
}
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity, maskSurface, maskTransform);
|
||||
}
|
||||
|
||||
/* If this frame has only a trivial clipPath, set up cairo's clipping now so
|
||||
* we can just do normal painting and get it clipped appropriately.
|
||||
*/
|
||||
if (clipPathFrame && isTrivialClip) {
|
||||
if (shouldApplyClipPath) {
|
||||
context.Save();
|
||||
clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
|
||||
} else if (!clipPathFrame && svgReset->HasClipPath()) {
|
||||
} else if (shouldApplyBasicShape) {
|
||||
context.Save();
|
||||
nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
|
||||
}
|
||||
|
||||
/* Paint the child */
|
||||
if (effectProperties.HasValidFilter() && !aParams.builder->IsForGenerateGlyphMask()) {
|
||||
RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
|
||||
offsetToUserSpace);
|
||||
target->SetMatrix(matrixAutoSaveRestore.Matrix());
|
||||
BasicLayerManager* basic = static_cast<BasicLayerManager*>(aParams.layerManager);
|
||||
RefPtr<gfxContext> oldCtx = basic->GetTarget();
|
||||
basic->SetTarget(target);
|
||||
aParams.layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
|
||||
aParams.builder);
|
||||
basic->SetTarget(oldCtx);
|
||||
|
||||
nsRegion dirtyRegion = aParams.dirtyRect - offsetToBoundingBox;
|
||||
gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(frame);
|
||||
nsFilterInstance::PaintFilteredFrame(frame, target->GetDrawTarget(),
|
||||
tm, &callback, &dirtyRegion);
|
||||
} else {
|
||||
target->SetMatrix(matrixAutoSaveRestore.Matrix());
|
||||
BasicLayerManager* basic = static_cast<BasicLayerManager*>(aParams.layerManager);
|
||||
RefPtr<gfxContext> oldCtx = basic->GetTarget();
|
||||
basic->SetTarget(target);
|
||||
aParams.layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
|
||||
aParams.builder);
|
||||
basic->SetTarget(oldCtx);
|
||||
}
|
||||
|
||||
if ((clipPathFrame && isTrivialClip) ||
|
||||
(!clipPathFrame && svgReset->HasClipPath())) {
|
||||
if (shouldApplyClipPath || shouldApplyBasicShape) {
|
||||
context.Restore();
|
||||
}
|
||||
|
||||
/* No more effects, we're done. */
|
||||
if (!complexEffects) {
|
||||
if (shouldGenerateMask) {
|
||||
target->PopGroupAndBlend();
|
||||
context.Restore();
|
||||
}
|
||||
|
||||
if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
MOZ_ASSERT(target != &aParams.ctx);
|
||||
BlendToTarget(aParams, target, targetOffset);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(!aParams.builder->IsForGenerateGlyphMask());
|
||||
|
||||
nsIFrame* frame = aParams.frame;
|
||||
DrawResult result = DrawResult::SUCCESS;
|
||||
bool hasSVGLayout = (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
if (!ValidateSVGFrame(aParams, hasSVGLayout, &result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (opacity != 1.0f || shouldGenerateMaskLayer ||
|
||||
(clipPathFrame && !isTrivialClip)) {
|
||||
target->PopGroupAndBlend();
|
||||
float opacity = ComputeOpacity(aParams);
|
||||
if (opacity == 0.0f) {
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
if (frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
RefPtr<DrawTarget> targetDT = target->GetDrawTarget();
|
||||
target = nullptr;
|
||||
RefPtr<SourceSurface> targetSurf = targetDT->Snapshot();
|
||||
gfxContext& context = aParams.ctx;
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint toUserSpace;
|
||||
nsPoint offsetToUserSpace;
|
||||
SetupContextMatrix(aParams, offsetToBoundingBox, toUserSpace,
|
||||
offsetToUserSpace);
|
||||
|
||||
context.SetMatrix(gfxMatrix()); // This will be restored right after.
|
||||
RefPtr<gfxPattern> pattern = new gfxPattern(targetSurf, Matrix::Translation(targetOffset.x, targetOffset.y));
|
||||
context.SetPattern(pattern);
|
||||
context.Paint();
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
|
||||
if (!effectProperties.HasValidFilter()) {
|
||||
return DrawResult::NOT_READY;
|
||||
}
|
||||
|
||||
// These are used if we require a temporary surface for a custom blend mode.
|
||||
IntPoint targetOffset;
|
||||
RefPtr<gfxContext> target =
|
||||
(aParams.frame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
|
||||
? RefPtr<gfxContext>(&aParams.ctx).forget()
|
||||
: CreateBlendTarget(aParams, targetOffset);
|
||||
if (!target) {
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
|
||||
/* Paint the child and apply filters */
|
||||
RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
|
||||
offsetToUserSpace);
|
||||
nsRegion dirtyRegion = aParams.dirtyRect - offsetToBoundingBox;
|
||||
gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(frame);
|
||||
nsFilterInstance::PaintFilteredFrame(frame, target->GetDrawTarget(),
|
||||
tm, &callback, &dirtyRegion);
|
||||
|
||||
if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
MOZ_ASSERT(target != &aParams.ctx);
|
||||
BlendToTarget(aParams, target, targetOffset);
|
||||
}
|
||||
|
||||
context.Restore();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,12 @@ public:
|
|||
static bool
|
||||
UsingEffectsForFrame(const nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Returns true if mask or clippath are currently applied to this frame.
|
||||
*/
|
||||
static bool
|
||||
UsingMaskOrClipPathForFrame(const nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Returns the size of the union of the border-box rects of all of
|
||||
* aNonSVGFrame's continuations.
|
||||
|
@ -147,7 +153,10 @@ public:
|
|||
* Paint non-SVG frame with SVG effects.
|
||||
*/
|
||||
static DrawResult
|
||||
PaintFramesWithEffects(const PaintFramesParams& aParams);
|
||||
PaintMaskAndClipPath(const PaintFramesParams& aParams);
|
||||
|
||||
static DrawResult
|
||||
PaintFilter(const PaintFramesParams& aParams);
|
||||
|
||||
/**
|
||||
* SVG frames expect to paint in SVG user units, which are equal to CSS px
|
||||
|
|
|
@ -41,7 +41,7 @@ payload:
|
|||
|
||||
# Note: This task is built server side without the context or tooling that
|
||||
# exist in tree so we must hard code the version
|
||||
image: 'taskcluster/decision:0.1.5'
|
||||
image: 'taskcluster/decision:0.1.6'
|
||||
|
||||
# Virtually no network or other potentially risky operations happen as part
|
||||
# of the task timeout aside from the initial clone. We intentionally have
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.1.5
|
||||
0.1.6
|
||||
|
|
|
@ -7,8 +7,6 @@ test `whoami` == 'root'
|
|||
apt-get update
|
||||
apt-get install -y --force-yes --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
jq \
|
||||
python \
|
||||
sudo
|
||||
|
||||
|
|
|
@ -13,22 +13,22 @@ if [ -f /etc/lsb-release ]; then
|
|||
|
||||
if [ "${DISTRIB_ID}" = "Ubuntu" -a "${DISTRIB_RELEASE}" = "16.04" ]; then
|
||||
HG_DEB=1
|
||||
HG_DIGEST=7b1fc1217e0dcaeea852b0af2dc559b1aafb704fbee7e29cbec75af57bacb84910a7ec92b5c33f04ee98f23b3a57f1fa451173fe7c8a96f58faefe319dc7dde1
|
||||
HG_SIZE=44878
|
||||
HG_FILENAME=mercurial_3.8.4_amd64.deb
|
||||
HG_DIGEST=09c7c80324158b755c23855d47caeb40b953218b1c89c7f5f21bbdea9de1d13a7ed5a7e647022ff626fb9674655baf05f6965361ccef3fa82b94d1fa8a684187
|
||||
HG_SIZE=44956
|
||||
HG_FILENAME=mercurial_3.9.1_amd64.deb
|
||||
|
||||
HG_COMMON_DIGEST=b476e2612e7495a1c7c5adfd84511aa7479e26cc9070289513ec705fbfc4c61806ce2dbcceca0e63f2e80669be416f3467a3cebb522dcb8a6aeb62cdd3df82f2
|
||||
HG_COMMON_SIZE=1818422
|
||||
HG_COMMON_FILENAME=mercurial-common_3.8.4_all.deb
|
||||
HG_COMMON_DIGEST=ef281d1368a8cf2363bc08c050aff3825028ba4d47d491e50e10f4c78574d5e87231a0096c7d9cb3439dd4b5172057a050e02946b4cf8b2bdf239ffd50a85d06
|
||||
HG_COMMON_SIZE=1847796
|
||||
HG_COMMON_FILENAME=mercurial-common_3.9.1_all.deb
|
||||
elif [ "${DISTRIB_ID}" = "Ubuntu" -a "${DISTRIB_RELEASE}" = "12.04" ]; then
|
||||
HG_DEB=1
|
||||
HG_DIGEST=96366b6baac26017a2ef9cd0bbbba4f18756e02921b0ff3541f677484d53d2041f01202b743ea8cdb96db58e88317da18befefc9711a085b054f9abc3dad1679
|
||||
HG_SIZE=54992
|
||||
HG_FILENAME=mercurial_3.8.4_amd64.deb
|
||||
HG_DIGEST=f816a6ca91129c0723527d98a2978c253a3f941f4358f9f8abd6f3ab8e8601ed3efc347828aac8f0d0762f819f9b777299e31037c39eb0c5af05aa76ac25c3bf
|
||||
HG_SIZE=55144
|
||||
HG_FILENAME=mercurial_3.9.1_amd64.deb
|
||||
|
||||
HG_COMMON_SIZE=2946616
|
||||
HG_COMMON_DIGEST=96c6bc305ae85f16885d0b6ac6800361d680811346a01338a56a2174a3c0ae5d86bbd827d93fe8c59d71acd2e1cc7d6e79e39a179836d5695cbfa3b370982ee5
|
||||
HG_COMMON_FILENAME=mercurial-common_3.8.4_all.deb
|
||||
HG_COMMON_DIGEST=ac2b2fab9f19438c77147dca8df5020d10b129052e6c5f77ebe9a4c21eb0cedb1acfe25b146577bf5e9b66f3d6cfca2474f7575adfba1b3849b66bf5bc321015
|
||||
HG_COMMON_SIZE=2993590
|
||||
HG_COMMON_FILENAME=mercurial-common_3.9.4_all.deb
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ try:
|
|||
except ImportError:
|
||||
import json
|
||||
|
||||
from cStringIO import StringIO
|
||||
|
||||
from mozprocess import ProcessHandler
|
||||
from mozharness.base.config import BaseConfig
|
||||
from mozharness.base.log import SimpleFileLogger, MultiFileLogger, \
|
||||
|
@ -458,28 +460,157 @@ class ScriptMixin(PlatformMixin):
|
|||
**retry_args
|
||||
)
|
||||
|
||||
def download_unpack(self, url, extract_to, extract_dirs=None,
|
||||
error_level=FATAL):
|
||||
"""Generic method to download and extract a compressed file.
|
||||
|
||||
The downloaded file will always be saved to the working directory and is not getting
|
||||
deleted after extracting.
|
||||
def _filter_entries(self, namelist, extract_dirs):
|
||||
"""Filter entries of the archive based on the specified list of to extract dirs."""
|
||||
filter_partial = functools.partial(fnmatch.filter, namelist)
|
||||
entries = itertools.chain(*map(filter_partial, extract_dirs or ['*']))
|
||||
|
||||
for entry in entries:
|
||||
yield entry
|
||||
|
||||
|
||||
def unzip(self, file_object, extract_to='.', extract_dirs='*', verbose=False):
|
||||
"""This method allows to extract a zip file without writing to disk first.
|
||||
|
||||
Args:
|
||||
file_object (object): Any file like object that is seekable.
|
||||
extract_to (str, optional): where to extract the compressed file.
|
||||
extract_dirs (list, optional): directories inside the archive file to extract.
|
||||
Defaults to '*'.
|
||||
"""
|
||||
compressed_file = StringIO(file_object.read())
|
||||
try:
|
||||
with zipfile.ZipFile(compressed_file) as bundle:
|
||||
entries = self._filter_entries(bundle.namelist(), extract_dirs)
|
||||
|
||||
for entry in entries:
|
||||
if verbose:
|
||||
self.info(' {}'.format(entry))
|
||||
bundle.extract(entry, path=extract_to)
|
||||
|
||||
# ZipFile doesn't preserve permissions during extraction:
|
||||
# http://bugs.python.org/issue15795
|
||||
fname = os.path.realpath(os.path.join(extract_to, entry))
|
||||
mode = bundle.getinfo(entry).external_attr >> 16 & 0x1FF
|
||||
# Only set permissions if attributes are available. Otherwise all
|
||||
# permissions will be removed eg. on Windows.
|
||||
if mode:
|
||||
os.chmod(fname, mode)
|
||||
|
||||
except zipfile.BadZipfile as e:
|
||||
self.exception('{}'.format(e.message))
|
||||
|
||||
|
||||
def deflate(self, file_object, mode, extract_to='.', extract_dirs='*', verbose=False):
|
||||
"""This method allows to extract a tar, tar.bz2 and tar.gz file without writing to disk first.
|
||||
|
||||
Args:
|
||||
file_object (object): Any file like object that is seekable.
|
||||
extract_to (str, optional): where to extract the compressed file.
|
||||
extract_dirs (list, optional): directories inside the archive file to extract.
|
||||
Defaults to `*`.
|
||||
verbose (bool, optional): whether or not extracted content should be displayed.
|
||||
Defaults to False.
|
||||
"""
|
||||
compressed_file = StringIO(file_object.read())
|
||||
t = tarfile.open(fileobj=compressed_file, mode=mode)
|
||||
t.extractall(path=extract_to)
|
||||
|
||||
|
||||
def download_unpack(self, url, extract_to='.', extract_dirs='*', verbose=False):
|
||||
"""Generic method to download and extract a compressed file without writing it to disk first.
|
||||
|
||||
Args:
|
||||
url (str): URL where the file to be downloaded is located.
|
||||
extract_to (str): directory where the downloaded file will
|
||||
be extracted to.
|
||||
extract_to (str, optional): directory where the downloaded file will
|
||||
be extracted to.
|
||||
extract_dirs (list, optional): directories inside the archive to extract.
|
||||
Defaults to `None`.
|
||||
error_level (str, optional): log level to use in case an error occurs.
|
||||
Defaults to `FATAL`.
|
||||
Defaults to `*`. It currently only applies to zip files.
|
||||
|
||||
Raises:
|
||||
IOError: on `filename` file not found.
|
||||
|
||||
"""
|
||||
dirs = self.query_abs_dirs()
|
||||
archive = self.download_file(url, parent_dir=dirs['abs_work_dir'],
|
||||
error_level=error_level)
|
||||
self.unpack(archive, extract_to, extract_dirs=extract_dirs,
|
||||
error_level=error_level)
|
||||
# Many scripts overwrite this method and set extract_dirs to None
|
||||
extract_dirs = '*' if extract_dirs is None else extract_dirs
|
||||
EXTENSION_TO_MIMETYPE = {
|
||||
'bz2': 'application/x-bzip2',
|
||||
'gz': 'application/x-gzip',
|
||||
'tar': 'application/x-tar',
|
||||
'zip': 'application/zip',
|
||||
}
|
||||
MIMETYPES = {
|
||||
'application/x-bzip2': {
|
||||
'function': self.deflate,
|
||||
'kwargs': {'mode': 'r:bz2'},
|
||||
},
|
||||
'application/x-gzip': {
|
||||
'function': self.deflate,
|
||||
'kwargs': {'mode': 'r:gz'},
|
||||
},
|
||||
'application/x-tar': {
|
||||
'function': self.deflate,
|
||||
'kwargs': {'mode': 'r'},
|
||||
},
|
||||
'application/zip': {
|
||||
'function': self.unzip,
|
||||
},
|
||||
}
|
||||
|
||||
parsed_url = urlparse.urlparse(url)
|
||||
|
||||
# In case we're referrencing a file without file://
|
||||
if parsed_url.scheme == '':
|
||||
if not os.path.isfile(url):
|
||||
raise IOError('Could not find file to extract: {}'.format(url))
|
||||
|
||||
url = 'file://%s' % os.path.abspath(url)
|
||||
parsed_fd = urlparse.urlparse(url)
|
||||
|
||||
request = urllib2.Request(url)
|
||||
response = urllib2.urlopen(request)
|
||||
|
||||
if parsed_url.scheme == 'file':
|
||||
filename = url.split('/')[-1]
|
||||
# XXX: bz2/gz instead of tar.{bz2/gz}
|
||||
extension = filename[filename.rfind('.')+1:]
|
||||
mimetype = EXTENSION_TO_MIMETYPE[extension]
|
||||
else:
|
||||
mimetype = response.headers.type
|
||||
|
||||
self.debug('Url: {}'.format(url))
|
||||
self.debug('Mimetype: {}'.format(mimetype))
|
||||
self.debug('Content-Encoding {}'.format(response.headers.get('Content-Encoding')))
|
||||
|
||||
function = MIMETYPES[mimetype]['function']
|
||||
kwargs = {
|
||||
'file_object': response,
|
||||
'extract_to': extract_to,
|
||||
'extract_dirs': extract_dirs,
|
||||
'verbose': verbose,
|
||||
}
|
||||
kwargs.update(MIMETYPES[mimetype].get('kwargs', {}))
|
||||
|
||||
self.info('Downloading and extracting to {} these dirs {} from {}'.format(
|
||||
extract_to,
|
||||
', '.join(extract_dirs),
|
||||
url,
|
||||
))
|
||||
retry_args = dict(
|
||||
failure_status=None,
|
||||
retry_exceptions=(urllib2.HTTPError, urllib2.URLError,
|
||||
httplib.BadStatusLine,
|
||||
socket.timeout, socket.error),
|
||||
error_message="Can't download from {}".format(url),
|
||||
error_level=FATAL,
|
||||
)
|
||||
self.retry(
|
||||
function,
|
||||
kwargs=kwargs,
|
||||
**retry_args
|
||||
)
|
||||
|
||||
|
||||
def load_json_url(self, url, error_level=None, *args, **kwargs):
|
||||
""" Returns a json object from a url (it retries). """
|
||||
|
@ -1409,12 +1540,6 @@ class ScriptMixin(PlatformMixin):
|
|||
IOError: on `filename` file not found.
|
||||
|
||||
"""
|
||||
def _filter_entries(namelist):
|
||||
"""Filter entries of the archive based on the specified list of to extract dirs."""
|
||||
filter_partial = functools.partial(fnmatch.filter, namelist)
|
||||
for entry in itertools.chain(*map(filter_partial, extract_dirs or ['*'])):
|
||||
yield entry
|
||||
|
||||
if not os.path.isfile(filename):
|
||||
raise IOError('Could not find file to extract: %s' % filename)
|
||||
|
||||
|
@ -1422,7 +1547,7 @@ class ScriptMixin(PlatformMixin):
|
|||
try:
|
||||
self.info('Using ZipFile to extract {} to {}'.format(filename, extract_to))
|
||||
with zipfile.ZipFile(filename) as bundle:
|
||||
for entry in _filter_entries(bundle.namelist()):
|
||||
for entry in self._filter_entries(bundle.namelist(), extract_dirs):
|
||||
if verbose:
|
||||
self.info(' %s' % entry)
|
||||
bundle.extract(entry, path=extract_to)
|
||||
|
@ -1444,7 +1569,7 @@ class ScriptMixin(PlatformMixin):
|
|||
try:
|
||||
self.info('Using TarFile to extract {} to {}'.format(filename, extract_to))
|
||||
with tarfile.open(filename) as bundle:
|
||||
for entry in _filter_entries(bundle.getnames()):
|
||||
for entry in self._filter_entries(bundle.getnames(), extract_dirs):
|
||||
if verbose:
|
||||
self.info(' %s' % entry)
|
||||
bundle.extract(entry, path=extract_to)
|
||||
|
|
|
@ -259,6 +259,50 @@ class TestScript(unittest.TestCase):
|
|||
self.assertTrue(error_logsize > 0,
|
||||
msg="error list not working properly")
|
||||
|
||||
def test_download_unpack(self):
|
||||
# NOTE: The action is called *download*, however, it can work for files in disk
|
||||
self.s = get_debug_script_obj()
|
||||
|
||||
archives_path = os.path.join(here, 'helper_files', 'archives')
|
||||
|
||||
# Test basic decompression
|
||||
for archive in ('archive.tar', 'archive.tar.bz2', 'archive.tar.gz', 'archive.zip'):
|
||||
self.s.download_unpack(
|
||||
url=os.path.join(archives_path, archive),
|
||||
extract_to=self.tmpdir
|
||||
)
|
||||
self.assertIn('script.sh', os.listdir(os.path.join(self.tmpdir, 'bin')))
|
||||
self.assertIn('lorem.txt', os.listdir(self.tmpdir))
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
# Test permissions for extracted entries from zip archive
|
||||
self.s.download_unpack(
|
||||
url=os.path.join(archives_path, 'archive.zip'),
|
||||
extract_to=self.tmpdir,
|
||||
)
|
||||
file_stats = os.stat(os.path.join(self.tmpdir, 'bin', 'script.sh'))
|
||||
orig_fstats = os.stat(os.path.join(archives_path, 'reference', 'bin', 'script.sh'))
|
||||
self.assertEqual(file_stats.st_mode, orig_fstats.st_mode)
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
# Test unzip specific dirs only
|
||||
self.s.download_unpack(
|
||||
url=os.path.join(archives_path, 'archive.zip'),
|
||||
extract_to=self.tmpdir,
|
||||
extract_dirs=['bin/*']
|
||||
)
|
||||
self.assertIn('bin', os.listdir(self.tmpdir))
|
||||
self.assertNotIn('lorem.txt', os.listdir(self.tmpdir))
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
# Test for invalid filenames (Windows only)
|
||||
if PYWIN32:
|
||||
with self.assertRaises(IOError):
|
||||
self.s.download_unpack(
|
||||
url=os.path.join(archives_path, 'archive_invalid_filename.zip'),
|
||||
extract_to=self.tmpdir
|
||||
)
|
||||
|
||||
def test_unpack(self):
|
||||
self.s = get_debug_script_obj()
|
||||
|
||||
|
|
|
@ -15,12 +15,9 @@ var passwordmanager = null;
|
|||
|
||||
// password-manager lists
|
||||
var signons = [];
|
||||
var rejects = [];
|
||||
var deletedSignons = [];
|
||||
var deletedRejects = [];
|
||||
|
||||
var signonsTree;
|
||||
var rejectsTree;
|
||||
|
||||
var showingPasswords = false;
|
||||
|
||||
|
@ -34,7 +31,6 @@ function Startup() {
|
|||
kObserverService.addObserver(signonReloadDisplay, "passwordmgr-storage-changed", false);
|
||||
|
||||
signonsTree = document.getElementById("signonsTree");
|
||||
rejectsTree = document.getElementById("rejectsTree");
|
||||
}
|
||||
|
||||
function Shutdown() {
|
||||
|
@ -59,17 +55,6 @@ var signonReloadDisplay = {
|
|||
_filterPasswords();
|
||||
}
|
||||
break;
|
||||
case "hostSavingEnabled":
|
||||
case "hostSavingDisabled":
|
||||
if (!rejectsTree) {
|
||||
return;
|
||||
}
|
||||
rejects.length = 0;
|
||||
if (lastRejectSortColumn == "hostname") {
|
||||
lastRejectSortAscending = !lastRejectSortAscending; // prevents sort from being reversed
|
||||
}
|
||||
LoadRejects();
|
||||
break;
|
||||
}
|
||||
kObserverService.notifyObservers(null, "passwordmgr-dialog-updated", null);
|
||||
}
|
||||
|
|
|
@ -1,115 +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/. */
|
||||
|
||||
/*** =================== REJECTED SIGNONS CODE =================== ***/
|
||||
|
||||
Components.utils.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
function RejectsStartup() {
|
||||
LoadRejects();
|
||||
|
||||
let treecols = document.getElementsByTagName("treecols")[0];
|
||||
treecols.addEventListener("click", HandleTreeColumnClick.bind(null, RejectColumnSort));
|
||||
}
|
||||
|
||||
var rejectsTreeView = {
|
||||
rowCount : 0,
|
||||
setTree : function(tree) {},
|
||||
getImageSrc : function(row, column) {},
|
||||
getProgressMode : function(row, column) {},
|
||||
getCellValue : function(row, column) {},
|
||||
getCellText : function(row, column) {
|
||||
var rv="";
|
||||
if (column.id=="rejectCol") {
|
||||
rv = rejects[row].host;
|
||||
}
|
||||
return rv;
|
||||
},
|
||||
isSeparator : function(index) { return false; },
|
||||
isSorted: function() { return false; },
|
||||
isContainer : function(index) { return false; },
|
||||
cycleHeader : function(column) {},
|
||||
getRowProperties : function(row) { return ""; },
|
||||
getColumnProperties : function(column) { return ""; },
|
||||
getCellProperties : function(row, column) {
|
||||
if (column.element.getAttribute("id") == "rejectCol")
|
||||
return "ltr";
|
||||
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
function Reject(number, host) {
|
||||
this.number = number;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
function LoadRejects() {
|
||||
var hosts = passwordmanager.getAllDisabledHosts();
|
||||
rejects = hosts.map(function(host, i) { return new Reject(i, host); });
|
||||
rejectsTreeView.rowCount = rejects.length;
|
||||
|
||||
// sort and display the table
|
||||
rejectsTree.view = rejectsTreeView;
|
||||
RejectColumnSort(lastRejectSortColumn);
|
||||
|
||||
var element = document.getElementById("removeAllRejects");
|
||||
if (rejects.length == 0) {
|
||||
element.setAttribute("disabled", "true");
|
||||
} else {
|
||||
element.removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
function RejectSelected() {
|
||||
var selections = GetTreeSelections(rejectsTree);
|
||||
if (selections.length) {
|
||||
document.getElementById("removeReject").removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
function DeleteReject() {
|
||||
DeleteSelectedItemFromTree(rejectsTree, rejectsTreeView,
|
||||
rejects, deletedRejects,
|
||||
"removeReject", "removeAllRejects");
|
||||
FinalizeRejectDeletions();
|
||||
}
|
||||
|
||||
function DeleteAllRejects() {
|
||||
DeleteAllFromTree(rejectsTree, rejectsTreeView,
|
||||
rejects, deletedRejects,
|
||||
"removeReject", "removeAllRejects");
|
||||
FinalizeRejectDeletions();
|
||||
}
|
||||
|
||||
function FinalizeRejectDeletions() {
|
||||
for (var r=0; r<deletedRejects.length; r++) {
|
||||
passwordmanager.setLoginSavingEnabled(deletedRejects[r].host, true);
|
||||
}
|
||||
deletedRejects.length = 0;
|
||||
}
|
||||
|
||||
function HandleRejectKeyPress(e) {
|
||||
if (e.keyCode == KeyEvent.DOM_VK_DELETE ||
|
||||
(AppConstants.platform == "macosx" &&
|
||||
e.keyCode == KeyEvent.DOM_VK_BACK_SPACE))
|
||||
{
|
||||
DeleteReject();
|
||||
}
|
||||
}
|
||||
|
||||
var lastRejectSortColumn = "host";
|
||||
var lastRejectSortAscending = false;
|
||||
|
||||
function RejectColumnSort(column) {
|
||||
lastRejectSortAscending =
|
||||
SortTree(rejectsTree, rejectsTreeView, rejects,
|
||||
column, lastRejectSortColumn, lastRejectSortAscending);
|
||||
lastRejectSortColumn = column;
|
||||
|
||||
// set the sortDirection attribute to get the styling going
|
||||
var sortedCol = document.getElementById("rejectCol");
|
||||
sortedCol.setAttribute("sortDirection", lastRejectSortAscending ?
|
||||
"ascending" : "descending");
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
<?xml version="1.0"?> <!-- -*- Mode: SGML; 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog SYSTEM "chrome://passwordmgr/locale/passwordManager.dtd" >
|
||||
|
||||
<prefwindow id="SignonViewerExceptionDialog"
|
||||
windowtype="Toolkit:PasswordManagerExceptions"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
buttons="accept"
|
||||
buttonlabelaccept="&closebutton.label;"
|
||||
onload="Startup(); RejectsStartup();"
|
||||
onunload="Shutdown();"
|
||||
title="&savedLoginsExceptions.title;"
|
||||
persist="width height screenX screenY">
|
||||
|
||||
<prefpane id="SignonViewerDialogPane" flex="1">
|
||||
<script type="application/javascript" src="chrome://passwordmgr/content/passwordManagerCommon.js"/>
|
||||
<script type="application/javascript" src="chrome://passwordmgr/content/passwordManagerExceptions.js"/>
|
||||
|
||||
<vbox id="rejectedsites" flex="1">
|
||||
<description control="rejectsTree">&savedLoginsExceptions.desc;</description>
|
||||
<separator class="thin"/>
|
||||
<tree id="rejectsTree" flex="1" style="height: 10em;" hidecolumnpicker="true"
|
||||
onkeypress="HandleRejectKeyPress(event)"
|
||||
onselect="RejectSelected();">
|
||||
<treecols>
|
||||
<treecol id="rejectCol" label="&treehead.site.label;" flex="5"
|
||||
data-field-name="host" sortDirection="ascending"/>
|
||||
</treecols>
|
||||
<treechildren/>
|
||||
</tree>
|
||||
<separator class="thin"/>
|
||||
<hbox>
|
||||
<button id="removeReject" disabled="true" icon="remove"
|
||||
accesskey="&remove.accesskey;"
|
||||
label="&remove.label;" oncommand="DeleteReject();"/>
|
||||
<button id="removeAllRejects"
|
||||
accesskey="&removeall.accesskey;"
|
||||
icon="clear" label="&removeall.label;"
|
||||
oncommand="DeleteAllRejects();"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</prefpane>
|
||||
</prefwindow>
|
|
@ -7,7 +7,5 @@ toolkit.jar:
|
|||
content/passwordmgr/login.xml (content/login.xml)
|
||||
* content/passwordmgr/passwordManager.xul (content/passwordManager.xul)
|
||||
content/passwordmgr/passwordManager.js (content/passwordManager.js)
|
||||
content/passwordmgr/passwordManagerExceptions.js (content/passwordManagerExceptions.js)
|
||||
content/passwordmgr/passwordManagerExceptions.xul (content/passwordManagerExceptions.xul)
|
||||
content/passwordmgr/passwordManagerCommon.js (content/passwordManagerCommon.js)
|
||||
content/passwordmgr/recipes.json (content/recipes.json)
|
||||
|
|
|
@ -38,6 +38,7 @@ support-files =
|
|||
subtst_notifications_change_p.html
|
||||
[browser_DOMFormHasPassword.js]
|
||||
[browser_DOMInputPasswordAdded.js]
|
||||
[browser_exceptions_dialog.js]
|
||||
[browser_filldoorhanger.js]
|
||||
[browser_formless_submit_chrome.js]
|
||||
[browser_hasInsecureLoginForms.js]
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const LOGIN_HOST = "http://example.com";
|
||||
|
||||
function openExceptionsDialog() {
|
||||
return window.openDialog(
|
||||
"chrome://browser/content/preferences/permissions.xul",
|
||||
"Toolkit:PasswordManagerExceptions", "",
|
||||
{
|
||||
blockVisible: true,
|
||||
sessionVisible: false,
|
||||
allowVisible: false,
|
||||
hideStatusColumn: true,
|
||||
prefilledHost: "",
|
||||
permissionType: "login-saving"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function countDisabledHosts(dialog) {
|
||||
let doc = dialog.document;
|
||||
let rejectsTree = doc.getElementById("permissionsTree");
|
||||
|
||||
return rejectsTree.view.rowCount;
|
||||
}
|
||||
|
||||
function promiseStorageChanged(expectedData) {
|
||||
function observer(subject, data) {
|
||||
return data == expectedData && subject.QueryInterface(Ci.nsISupportsString).data == LOGIN_HOST;
|
||||
}
|
||||
|
||||
return TestUtils.topicObserved("passwordmgr-storage-changed", observer);
|
||||
}
|
||||
|
||||
add_task(function* test_disable() {
|
||||
let dialog = openExceptionsDialog();
|
||||
let promiseChanged = promiseStorageChanged("hostSavingDisabled");
|
||||
|
||||
yield BrowserTestUtils.waitForEvent(dialog, "load");
|
||||
Services.logins.setLoginSavingEnabled(LOGIN_HOST, false);
|
||||
yield promiseChanged;
|
||||
is(countDisabledHosts(dialog), 1, "Verify disabled host added");
|
||||
yield BrowserTestUtils.closeWindow(dialog);
|
||||
});
|
||||
|
||||
add_task(function* test_enable() {
|
||||
let dialog = openExceptionsDialog();
|
||||
let promiseChanged = promiseStorageChanged("hostSavingEnabled");
|
||||
|
||||
yield BrowserTestUtils.waitForEvent(dialog, "load");
|
||||
Services.logins.setLoginSavingEnabled(LOGIN_HOST, true);
|
||||
yield promiseChanged;
|
||||
is(countDisabledHosts(dialog), 0, "Verify disabled host removed");
|
||||
yield BrowserTestUtils.closeWindow(dialog);
|
||||
});
|
|
@ -12,9 +12,7 @@ function test() {
|
|||
let pmDialog = window.openDialog(
|
||||
"chrome://passwordmgr/content/passwordManager.xul",
|
||||
"Toolkit:PasswordManager", "");
|
||||
let pmexDialog = window.openDialog(
|
||||
"chrome://passwordmgr/content/passwordManagerExceptions.xul",
|
||||
"Toolkit:PasswordManagerExceptions", "");
|
||||
|
||||
let logins = [];
|
||||
let loginCounter = 0;
|
||||
let loginOrder = null;
|
||||
|
@ -48,14 +46,6 @@ function test() {
|
|||
is(countLogins(), 0, "Verify all logins removed");
|
||||
runNextTest();
|
||||
break;
|
||||
case 9:
|
||||
is(countDisabledHosts(), 1, "Verify disabled host added");
|
||||
runNextTest();
|
||||
break;
|
||||
case 10:
|
||||
is(countDisabledHosts(), 0, "Verify disabled host removed");
|
||||
runNextTest();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,12 +65,6 @@ function test() {
|
|||
is(logins.length, LOGIN_COUNT, "Verify logins created");
|
||||
}
|
||||
|
||||
function countDisabledHosts() {
|
||||
let doc = pmexDialog.document;
|
||||
let rejectsTree = doc.getElementById("rejectsTree");
|
||||
return rejectsTree.view.rowCount;
|
||||
}
|
||||
|
||||
function countLogins() {
|
||||
let doc = pmDialog.document;
|
||||
let signonsTree = doc.getElementById("signonsTree");
|
||||
|
@ -134,19 +118,10 @@ function test() {
|
|||
case 8: // remove all logins
|
||||
Services.logins.removeAllLogins();
|
||||
break;
|
||||
case 9: // save a disabled host
|
||||
pmDialog.close();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
Services.logins.setLoginSavingEnabled(LOGIN_HOST, false);
|
||||
}, pmexDialog);
|
||||
break;
|
||||
case 10: // remove a disabled host
|
||||
Services.logins.setLoginSavingEnabled(LOGIN_HOST, true);
|
||||
break;
|
||||
case 11: // finish
|
||||
case 9: // finish
|
||||
Services.obs.removeObserver(
|
||||
testObserver, "passwordmgr-dialog-updated", false);
|
||||
pmexDialog.close();
|
||||
pmDialog.close();
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!ENTITY savedLogins.title "Saved Logins">
|
||||
<!ENTITY savedLoginsExceptions.title "Exceptions - Saved Logins">
|
||||
<!ENTITY savedLoginsExceptions.desc "Logins for the following sites will not be saved:">
|
||||
|
||||
<!ENTITY closebutton.label "Close">
|
||||
<!ENTITY closebutton.accesskey "C">
|
||||
|
|
|
@ -46,10 +46,14 @@ const ADDONS = {
|
|||
id: "jid0-GXjLLfbCoAx0LcltEdFrEkQdQPI@jetpack", minVersion: "3.0.10",
|
||||
},
|
||||
|
||||
"PersonasPlus": {
|
||||
"PersonasPlus": { // PersonasPlus
|
||||
id: "personas@christopher.beard", minVersion: "1.8.0",
|
||||
},
|
||||
|
||||
"ACR": { // Add-on Compatibility Reporter
|
||||
id: "compatibility@addons.mozilla.org", minVersion: "2.2.0",
|
||||
},
|
||||
|
||||
// Add-ons used for testing
|
||||
"test1": {
|
||||
id: "bootstrap1@tests.mozilla.org", minVersion: "1.0",
|
||||
|
@ -62,10 +66,8 @@ const ADDONS = {
|
|||
|
||||
// NOTE: Do not modify sets or policies after they have already been
|
||||
// published to users. They must remain unchanged to provide valid data.
|
||||
const set1 = [ADDONS.Emoji,
|
||||
ADDONS.ASP,
|
||||
ADDONS.DYTV];
|
||||
|
||||
// Set 2 used during 48 Beta cycle. Kept here for historical reasons.
|
||||
const set2 = [ADDONS.Greasemonkey,
|
||||
ADDONS.DYTV,
|
||||
ADDONS.VDH,
|
||||
|
@ -76,16 +78,46 @@ const set2 = [ADDONS.Greasemonkey,
|
|||
ADDONS.ASP,
|
||||
ADDONS.PersonasPlus];
|
||||
|
||||
const set49Release = [
|
||||
ADDONS.Greasemonkey,
|
||||
ADDONS.DYTV,
|
||||
ADDONS.VDH,
|
||||
ADDONS.Lightbeam,
|
||||
ADDONS.ABP,
|
||||
ADDONS.uBlockOrigin,
|
||||
ADDONS.Emoji,
|
||||
ADDONS.ASP,
|
||||
ADDONS.PersonasPlus,
|
||||
ADDONS.ACR
|
||||
];
|
||||
|
||||
// These are only the add-ons in the Add-Ons Manager Discovery
|
||||
// pane. This set is here in case we need to reduce add-ons
|
||||
// exposure live on Release.
|
||||
const set49PaneOnly = [
|
||||
ADDONS.ABP,
|
||||
ADDONS.VDH,
|
||||
ADDONS.Emoji,
|
||||
ADDONS.ASP,
|
||||
ADDONS.ACR
|
||||
]
|
||||
|
||||
// We use these named policies to correlate the telemetry
|
||||
// data with them, in order to understand how each set
|
||||
// is behaving in the wild.
|
||||
const RolloutPolicy = {
|
||||
"1a": { addons: set1, webextensions: true },
|
||||
// Used during 48 Beta cycle
|
||||
"2a": { addons: set2, webextensions: true },
|
||||
|
||||
"1b": { addons: set1, webextensions: false },
|
||||
"2b": { addons: set2, webextensions: false },
|
||||
|
||||
// Set agreed for Release 49
|
||||
"49a": { addons: set49Release, webextensions: true },
|
||||
"49b": { addons: set49Release, webextensions: false },
|
||||
|
||||
// Smaller set that can be used for Release 49
|
||||
"49limiteda": { addons: set49PaneOnly, webextensions: true },
|
||||
"49limitedb": { addons: set49PaneOnly, webextensions: false },
|
||||
|
||||
"xpcshell-test": { addons: [ADDONS.test1, ADDONS.test2], webextensions: false },
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
Coverity model file in order to avoid false-positive
|
||||
*/
|
||||
|
||||
#define NULL (void *)0
|
||||
|
||||
typedef unsigned char jsbytecode;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
static const uint16_t CHUNK_HEAD_SIZE = 8;
|
||||
|
||||
void assert(bool expr) {
|
||||
if (!expr) {
|
||||
__coverity_panic__();
|
||||
}
|
||||
}
|
||||
|
||||
#define ERREXIT(cinfo, err) __coverity_panic__();
|
||||
|
||||
void MOZ_ASSUME_UNREACHABLE(char * str) {
|
||||
__coverity_panic__();
|
||||
}
|
||||
|
||||
static void MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename,
|
||||
int aLine) {
|
||||
__coverity_panic__();
|
||||
}
|
||||
|
||||
static void MOZ_ReportCrash(const char* aStr, const char* aFilename,
|
||||
int aLine) {
|
||||
__coverity_panic__();
|
||||
}
|
||||
|
||||
#define MOZ_ASSERT(expr, msg) assert(!!(expr))
|
||||
|
||||
#define MOZ_ASSERT(expr) assert(!!(expr))
|
||||
|
||||
#define NS_ASSERTION(expr, msg) assert(!!(expr))
|
||||
|
||||
#define PORT_Assert(expr) assert(!!(expr))
|
||||
|
||||
#define PR_ASSERT(expr) assert(!!(expr))
|
||||
|
||||
int GET_JUMP_OFFSET(jsbytecode* pc) {
|
||||
__coverity_tainted_data_sanitize__(&pc[1]);
|
||||
__coverity_tainted_data_sanitize__(&pc[2]);
|
||||
__coverity_tainted_data_sanitize__(&pc[3]);
|
||||
__coverity_tainted_data_sanitize__(&pc[4]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Data sanity checkers
|
||||
#define XPT_SWAB16(data) __coverity_tainted_data_sanitize__(&data)
|
||||
|
||||
#define XPT_SWAB32(data) __coverity_tainted_data_sanitize__(&data)
|
||||
|
||||
|
||||
static unsigned GET_UINT24(const jsbytecode* pc) {
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(pc));
|
||||
//return unsigned((pc[1] << 16) | (pc[2] << 8) | pc[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
class HeaderParser {
|
||||
|
||||
private:
|
||||
class ChunkHeader {
|
||||
|
||||
uint8_t mRaw[CHUNK_HEAD_SIZE];
|
||||
|
||||
HeaderParser::ChunkHeader::ChunkSize() const {
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&mRaw[4]));
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&mRaw[5]));
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&mRaw[6]));
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&mRaw[7]));
|
||||
|
||||
return ((mRaw[7] << 24) | (mRaw[6] << 16) | (mRaw[5] << 8) | (mRaw[4]));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr,
|
||||
const char* aFile, int32_t aLine) {
|
||||
__coverity_panic__();
|
||||
}
|
||||
|
||||
static inline void Swap(uint32_t* value) {
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&value));
|
||||
*value = (*value >> 24) |
|
||||
((*value >> 8) & 0x0000ff00) |
|
||||
((*value << 8) & 0x00ff0000) |
|
||||
(*value << 24);
|
||||
}
|
||||
|
||||
static uint32_t xtolong (const uint8_t *ll) {
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&ll[0]));
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&ll[1]));
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&ll[2]));
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&ll[3]));
|
||||
|
||||
return (uint32_t)( (ll [0] << 0) |
|
||||
(ll [1] << 8) |
|
||||
(ll [2] << 16) |
|
||||
(ll [3] << 24) );
|
||||
}
|
||||
|
||||
class ByteReader {
|
||||
public:
|
||||
const uint8_t* Read(size_t aCount);
|
||||
uint32_t ReadU24() {
|
||||
const uint8_t *ptr = Read(3);
|
||||
if (!ptr) {
|
||||
MOZ_ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&ptr[0]));
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&ptr[1]));
|
||||
__coverity_tainted_data_sanitize__(static_cast<void*>(&ptr[2]));
|
||||
return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
|
||||
}
|
||||
};
|
||||
|
|
@ -1392,7 +1392,7 @@ nsNativeThemeCocoa::DrawButton(CGContextRef cgContext, ThemeButtonKind inKind,
|
|||
if (inState.HasState(NS_EVENT_STATE_FOCUS) && isActive)
|
||||
bdi.adornment |= kThemeAdornmentFocus;
|
||||
|
||||
if (inIsDefault && !isDisabled && isActive &&
|
||||
if (inIsDefault && !isDisabled &&
|
||||
!inState.HasState(NS_EVENT_STATE_ACTIVE)) {
|
||||
bdi.adornment |= kThemeAdornmentDefault;
|
||||
bdi.animation.time.start = 0;
|
||||
|
@ -2468,11 +2468,22 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext,
|
|||
|
||||
case NS_THEME_BUTTON:
|
||||
if (IsDefaultButton(aFrame)) {
|
||||
if (!IsDisabled(aFrame, eventState) && FrameIsInActiveWindow(aFrame) &&
|
||||
// Check whether the default button is in a document that does not
|
||||
// match the :-moz-window-inactive pseudoclass. This activeness check
|
||||
// is different from the other "active window" checks in this file
|
||||
// because we absolutely need the button's default button appearance to
|
||||
// be in sync with its text color, and the text color is changed by
|
||||
// such a :-moz-window-inactive rule. (That's because on 10.10 and up,
|
||||
// default buttons in active windows have blue background and white
|
||||
// text, and default buttons in inactive windows have white background
|
||||
// and black text.)
|
||||
EventStates docState = aFrame->GetContent()->OwnerDoc()->GetDocumentState();
|
||||
bool isInActiveWindow = !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
|
||||
if (!IsDisabled(aFrame, eventState) && isInActiveWindow &&
|
||||
!QueueAnimatedContentForRefresh(aFrame->GetContent(), 10)) {
|
||||
NS_WARNING("Unable to animate button!");
|
||||
}
|
||||
DrawButton(cgContext, kThemePushButton, macRect, true,
|
||||
DrawButton(cgContext, kThemePushButton, macRect, isInActiveWindow,
|
||||
kThemeButtonOff, kThemeAdornmentNone, eventState, aFrame);
|
||||
} else if (IsButtonTypeMenu(aFrame)) {
|
||||
DrawDropdown(cgContext, macRect, eventState, aWidgetType, aFrame);
|
||||
|
|
Загрузка…
Ссылка в новой задаче