Bug 1689816 - Implement <tabpanels> and <deck> without XUL layout. r=Gijs,Jamie,morgan,preferences-reviewers,mconley,TYLin

Gijs for front-end bits, layout for the new CSS properties and the
removal of nsDeckFrame / nsStackLayout, Jamie and Morgan for the a11y
changes.

As discussed in the bug, the main tricky part here is handling a11y
correctly. For <deck>, that's trivial (just use `visibility: hidden` to
hide the panels visually, while removing the unselected panels from the
a11y tree).

For <tabpanels> however we need to do something special. We do want to
hide stuff visually, but we want to preserve the contents in the a11y
tree.

For that, the easiest fix is introducing a new privileged CSS property
(-moz-subtree-hidden-only-visually), which takes care of not painting
the frame, but marks stuff offscreen in the accessibility tree. This is
not intended to be a property used widely.

Other than that, the changes are relatively straight-forward, though
some of the accessible/mac changes I could get a sanity-check on.

Differential Revision: https://phabricator.services.mozilla.com/D157875
This commit is contained in:
Emilio Cobos Álvarez 2022-09-27 04:18:16 +00:00
Родитель 2bb8defd02
Коммит 4e978b56b5
73 изменённых файлов: 341 добавлений и 1252 удалений

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

@ -75,7 +75,6 @@
#include "mozilla/Services.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "mozilla/SVGGeometryFrame.h"
#include "nsDeckFrame.h"
#include "XULAlertAccessible.h"
#include "XULComboboxAccessible.h"
@ -443,62 +442,19 @@ LocalAccessible* nsAccessibilityService::GetRootDocumentAccessible(
return nullptr;
}
void nsAccessibilityService::DeckPanelSwitched(PresShell* aPresShell,
nsIContent* aDeckNode,
nsIFrame* aPrevBoxFrame,
nsIFrame* aCurrentBoxFrame) {
void nsAccessibilityService::NotifyOfTabPanelVisibilityChange(
PresShell* aPresShell, Element* aPanel, bool aNowVisible) {
MOZ_ASSERT(aPanel->GetParent()->IsXULElement(nsGkAtoms::tabpanels));
DocAccessible* document = GetDocAccessible(aPresShell);
if (!document) {
return;
}
// A deck with a LocalAccessible is a tabpanels element.
const bool isTabPanels = document->HasAccessible(aDeckNode);
MOZ_ASSERT(!isTabPanels || aDeckNode->IsXULElement(nsGkAtoms::tabpanels),
"A deck with a LocalAccessible should be a tabpanels element");
if (aPrevBoxFrame) {
nsIContent* panelNode = aPrevBoxFrame->GetContent();
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree)) {
logging::MsgBegin("TREE", "deck panel unselected");
logging::Node("container", panelNode);
logging::Node("content", aDeckNode);
logging::MsgEnd();
}
#endif
if (isTabPanels) {
// Tabpanels are accessible even when not selected.
if (LocalAccessible* acc = document->GetAccessible(panelNode)) {
RefPtr<AccEvent> event =
new AccStateChangeEvent(acc, states::OFFSCREEN, true);
document->FireDelayedEvent(event);
}
} else {
document->ContentRemoved(panelNode);
}
}
if (aCurrentBoxFrame) {
nsIContent* panelNode = aCurrentBoxFrame->GetContent();
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree)) {
logging::MsgBegin("TREE", "deck panel selected");
logging::Node("container", panelNode);
logging::Node("content", aDeckNode);
logging::MsgEnd();
}
#endif
if (isTabPanels) {
// Tabpanels are accessible even when not selected, so we don't have to
// insert a LocalAccessible.
if (LocalAccessible* acc = document->GetAccessible(panelNode)) {
RefPtr<AccEvent> event =
new AccStateChangeEvent(acc, states::OFFSCREEN, false);
document->FireDelayedEvent(event);
}
} else {
document->ContentInserted(panelNode, panelNode->GetNextSibling());
}
if (LocalAccessible* acc = document->GetAccessible(aPanel)) {
RefPtr<AccEvent> event =
new AccStateChangeEvent(acc, states::OFFSCREEN, aNowVisible);
document->FireDelayedEvent(event);
}
}
@ -1128,16 +1084,6 @@ LocalAccessible* nsAccessibilityService::CreateAccessible(
// XUL accessibles.
if (!newAcc && content->IsXULElement()) {
// No accessible for not selected deck panel and its children.
if (!aContext->IsXULTabpanels()) {
nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent());
if (deckFrame && deckFrame->GetSelectedBox() != frame) {
if (aIsSubtreeHidden) *aIsSubtreeHidden = true;
return nullptr;
}
}
if (content->IsXULElement(nsGkAtoms::panel)) {
// We filter here instead of in the XUL map because
// if we filter there and return null, we still end up

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

@ -153,13 +153,6 @@ class nsAccessibilityService final : public mozilla::a11y::DocManager,
void GetStringRelationType(uint32_t aRelationType, nsAString& aString);
// nsAccesibilityService
/**
* Notification used to update the accessible tree when deck panel is
* switched.
*/
void DeckPanelSwitched(mozilla::PresShell* aPresShell, nsIContent* aDeckNode,
nsIFrame* aPrevBoxFrame, nsIFrame* aCurrentBoxFrame);
/**
* Notification used to update the accessible tree when new content is
* inserted.
@ -240,6 +233,10 @@ class nsAccessibilityService final : public mozilla::a11y::DocManager,
void NotifyOfComputedStyleChange(mozilla::PresShell* aPresShell,
nsIContent* aContent);
void NotifyOfTabPanelVisibilityChange(mozilla::PresShell* aPresShell,
mozilla::dom::Element* aPanel,
bool aVisible);
void NotifyOfResolutionChange(mozilla::PresShell* aPresShell,
float aResolution);

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

@ -14,7 +14,6 @@
#include "nsAccCache.h"
#include "nsAccessiblePivot.h"
#include "nsAccUtils.h"
#include "nsDeckFrame.h"
#include "nsEventShell.h"
#include "nsLayoutUtils.h"
#include "nsTextEquivUtils.h"
@ -1052,21 +1051,6 @@ LocalAccessible* DocAccessible::GetAccessibleOrContainer(
return nullptr;
}
// Check if node is in an unselected deck panel
if (aNoContainerIfPruned && currNode->IsXULElement()) {
if (nsIFrame* frame = currNode->AsContent()->GetPrimaryFrame()) {
nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent());
if (deckFrame && deckFrame->GetSelectedBox() != frame) {
// If deck is not a <tabpanels>, return null
nsIContent* parentFrameContent = deckFrame->GetContent();
if (!parentFrameContent ||
!parentFrameContent->IsXULElement(nsGkAtoms::tabpanels)) {
return nullptr;
}
}
}
}
// Check if node is in zero-sized map
if (aNoContainerIfPruned && currNode->IsHTMLElement(nsGkAtoms::map)) {
if (nsIFrame* frame = currNode->AsContent()->GetPrimaryFrame()) {

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

@ -50,7 +50,6 @@
#include "nsIContent.h"
#include "nsIFormControl.h"
#include "nsDeckFrame.h"
#include "nsLayoutUtils.h"
#include "nsPresContext.h"
#include "nsIFrame.h"
@ -70,6 +69,7 @@
#include "nsArrayUtils.h"
#include "nsWhitespaceTokenizer.h"
#include "nsAttrName.h"
#include "nsContainerFrame.h"
#include "mozilla/Assertions.h"
#include "mozilla/BasicEvents.h"
@ -324,22 +324,16 @@ uint64_t LocalAccessible::VisibilityState() const {
return states::INVISIBLE;
}
if (nsLayoutUtils::IsPopup(curFrame)) return 0;
// Offscreen state for background tab content and invisible for not selected
// deck panel.
nsIFrame* parentFrame = curFrame->GetParent();
nsDeckFrame* deckFrame = do_QueryFrame(parentFrame);
if (deckFrame && deckFrame->GetSelectedBox() != curFrame) {
if (deckFrame->GetContent()->IsXULElement(nsGkAtoms::tabpanels)) {
return states::OFFSCREEN;
}
MOZ_ASSERT_UNREACHABLE(
"Children of not selected deck panel are not accessible.");
return states::INVISIBLE;
if (nsLayoutUtils::IsPopup(curFrame)) {
return 0;
}
if (curFrame->StyleUIReset()->mMozSubtreeHiddenOnlyVisually) {
// Offscreen state for background tab content.
return states::OFFSCREEN;
}
nsIFrame* parentFrame = curFrame->GetParent();
// If contained by scrollable frame then check that at least 12 pixels
// around the object is visible, otherwise the object is offscreen.
nsIScrollableFrame* scrollableFrame = do_QueryFrame(parentFrame);

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

@ -13,7 +13,6 @@
#include "XULTabAccessible.h"
#include "HTMLFormControlAccessible.h"
#include "nsDeckFrame.h"
#include "nsObjCExceptions.h"
using namespace mozilla::a11y;
@ -126,26 +125,17 @@ enum CheckboxValue {
@implementation mozPaneAccessible
- (NSArray*)moxChildren {
if (!mGeckoAccessible->AsLocal()) return nil;
nsDeckFrame* deckFrame =
do_QueryFrame(mGeckoAccessible->AsLocal()->GetFrame());
nsIFrame* selectedFrame = deckFrame ? deckFrame->GetSelectedBox() : nullptr;
LocalAccessible* selectedAcc = nullptr;
if (selectedFrame) {
nsINode* node = selectedFrame->GetContent();
selectedAcc = mGeckoAccessible->AsLocal()->Document()->GetAccessible(node);
// By default, all tab panels are exposed in the a11y tree
// even if the tab they represent isn't the active tab. To
// prevent VoiceOver from navigating background tab content,
// only expose the tab panel that is currently on screen.
for (mozAccessible* child in [super moxChildren]) {
if (!([child state] & states::OFFSCREEN)) {
return [NSArray arrayWithObject:GetObjectOrRepresentedView(child)];
}
}
if (selectedAcc) {
mozAccessible* curNative = GetNativeFromGeckoAccessible(selectedAcc);
if (curNative)
return
[NSArray arrayWithObjects:GetObjectOrRepresentedView(curNative), nil];
}
return nil;
MOZ_ASSERT_UNREACHABLE("We have no on screen tab content?");
return @[];
}
@end

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

@ -22,7 +22,6 @@
// CSS display
testCSSAttrs("display_mozbox");
testCSSAttrs("display_mozinlinebox");
testCSSAttrs("display_mozdeck");
testCSSAttrs("display_mozpopup");
SimpleTest.finish();
@ -50,7 +49,6 @@
<vbox id="display_mozbox" style="display: -moz-box;" role="img"/>
<vbox id="display_mozinlinebox" style="display: -moz-inline-box;" role="img"/>
<vbox id="display_mozdeck" style="display: -moz-deck;" role="img"/>
<vbox id="display_mozpopup" style="display: -moz-popup;" role="img"/>
</hbox>

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

@ -2171,23 +2171,23 @@ var gBrowserInit = {
return;
}
if (gBrowser.selectedBrowser.isRemoteBrowser) {
// If the initial browser is remote, in order to optimize for first paint,
// we'll defer switching focus to that browser until it has painted.
this._firstContentWindowPaintDeferred.promise.then(() => {
// If focus didn't move while we were waiting for first paint, we're okay
// to move to the browser.
if (
document.commandDispatcher.focusedElement == initiallyFocusedElement
) {
gBrowser.selectedBrowser.focus();
}
});
} else {
// If the initial browser is not remote, we can focus the browser
// immediately with no paint performance impact.
gBrowser.selectedBrowser.focus();
}
// If the initial browser is remote, in order to optimize for first paint,
// we'll defer switching focus to that browser until it has painted.
// Otherwise use a regular promise to guarantee that mutationobserver
// microtasks that could affect focusability have run.
let promise = gBrowser.selectedBrowser.isRemoteBrowser
? this._firstContentWindowPaintDeferred.promise
: Promise.resolve();
promise.then(() => {
// If focus didn't move while we were waiting, we're okay to move to
// the browser.
if (
document.commandDispatcher.focusedElement == initiallyFocusedElement
) {
gBrowser.selectedBrowser.focus();
}
});
});
// Delay removing the attribute using requestAnimationFrame to avoid

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

@ -47,7 +47,7 @@ add_task(async function() {
Assert.equal(
win.document.activeElement,
expectedActiveElement,
uri + ": the active element is expected"
`${uri}: the active element is expected: ${win.document.activeElement?.nodeName}`
);
Assert.equal(win.gURLBar.value, "", uri + ": urlbar is empty");
Assert.ok(win.gURLBar.placeholder, uri + ": placeholder text is present");

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

@ -254,11 +254,7 @@ add_task(async function() {
// The widget is still fetching tabs, as we've neutered everything that
// provides them
is(
deck.selectedIndex,
"" + DECKINDEX_FETCHING,
"first deck entry is visible"
);
is(deck.selectedIndex, DECKINDEX_FETCHING, "first deck entry is visible");
// Tell the widget there are tabs available, but with zero clients.
mockedInternal.getTabClients = () => {
@ -269,7 +265,7 @@ add_task(async function() {
// The UI should be showing the "no clients" pane.
is(
deck.selectedIndex,
"" + DECKINDEX_NOCLIENTS,
DECKINDEX_NOCLIENTS,
"no-clients deck entry is visible"
);
@ -320,11 +316,7 @@ add_task(async function() {
await updateTabsPanel();
// The UI should be showing tabs!
is(
deck.selectedIndex,
"" + DECKINDEX_TABS,
"no-clients deck entry is visible"
);
is(deck.selectedIndex, DECKINDEX_TABS, "no-clients deck entry is visible");
let tabList = document.getElementById("PanelUI-remotetabs-tabslist");
let node = tabList.firstElementChild;
// First entry should be the client with the most-recent tab.
@ -467,7 +459,7 @@ add_task(async function() {
let subpanel = document.getElementById("PanelUI-remotetabs-main");
ok(!subpanel.hidden, "main pane is visible");
let deck = document.getElementById("PanelUI-remotetabs-deck");
is(deck.selectedIndex, "" + DECKINDEX_TABS, "we should be showing tabs");
is(deck.selectedIndex, DECKINDEX_TABS, "we should be showing tabs");
function checkTabsPage(tabsShownCount, showMoreLabel) {
let tabList = document.getElementById("PanelUI-remotetabs-tabslist");

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

@ -25,7 +25,7 @@ add_task(async function() {
);
is(
weavePrefsDeck.selectedIndex,
"0",
0,
"Should select the #noFxaAccount child node"
);

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

@ -103,7 +103,7 @@ add_task(async function test_infobar() {
let notif = showTranslationUI("fr");
is(
notif.state,
"" + Translation.STATE_OFFER,
Translation.STATE_OFFER,
"the infobar is offering translation"
);
is(
@ -117,7 +117,7 @@ add_task(async function test_infobar() {
notif._getAnonElt("translate").click();
is(
notif.state,
"" + Translation.STATE_TRANSLATING,
Translation.STATE_TRANSLATING,
"the infobar is in the translating state"
);
ok(
@ -134,14 +134,14 @@ add_task(async function test_infobar() {
info("Make the translation fail and check we are in the error state.");
notif.translation.failTranslation();
is(notif.state, "" + Translation.STATE_ERROR, "infobar in the error state");
is(notif.state, Translation.STATE_ERROR, "infobar in the error state");
checkURLBarIcon();
info("Click the try again button");
notif._getAnonElt("tryAgain").click();
is(
notif.state,
"" + Translation.STATE_TRANSLATING,
Translation.STATE_TRANSLATING,
"infobar in the translating state"
);
ok(
@ -162,7 +162,7 @@ add_task(async function test_infobar() {
notif.translation.finishTranslation();
is(
notif.state,
"" + Translation.STATE_TRANSLATED,
Translation.STATE_TRANSLATED,
"infobar in the translated state"
);
checkURLBarIcon(true);
@ -207,7 +207,7 @@ add_task(async function test_infobar() {
from.doCommand();
is(
notif.state,
"" + Translation.STATE_TRANSLATING,
Translation.STATE_TRANSLATING,
"infobar in the translating state"
);
ok(
@ -232,7 +232,7 @@ add_task(async function test_infobar() {
to.doCommand();
is(
notif.state,
"" + Translation.STATE_TRANSLATING,
Translation.STATE_TRANSLATING,
"infobar in the translating state"
);
ok(
@ -254,7 +254,7 @@ add_task(async function test_infobar() {
notif = showTranslationUI("fr");
is(
notif.state,
"" + Translation.STATE_OFFER,
Translation.STATE_OFFER,
"the infobar is offering translation"
);
is(
@ -267,7 +267,7 @@ add_task(async function test_infobar() {
notif._getAnonElt("translate").click();
is(
notif.state,
"" + Translation.STATE_TRANSLATING,
Translation.STATE_TRANSLATING,
"the infobar is in the translating state"
);
ok(
@ -332,7 +332,7 @@ add_task(async function test_infobar_using_page() {
let notif = notificationBox.getNotificationWithValue("translation");
is(
notif.state,
"" + Translation.STATE_OFFER,
Translation.STATE_OFFER,
"the infobar is offering translation"
);
is(

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

@ -468,7 +468,7 @@ class AsyncTabSwitcher {
let index = Array.prototype.indexOf.call(tabpanels.children, showPanel);
if (index != -1) {
this.log(`Switch to tab ${index} - ${this.tinfo(showTab)}`);
tabpanels.setAttribute("selectedIndex", index);
tabpanels.updateSelectedIndex(index);
if (showTab === this.requestedTab) {
if (requestedTabState == this.STATE_LOADED) {
// The new tab will be made visible in the next paint, record the expected

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

@ -397,9 +397,11 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left {
}
#tabbrowser-tabs {
/* overriding tabbox.css */
-moz-box-align: stretch;
margin-bottom: 0;
position: static;
z-index: auto;
}
/* Bookmark drag and drop styles */

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

@ -113,6 +113,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"object-fit",
"-moz-orient",
"-moz-osx-font-smoothing",
"-moz-subtree-hidden-only-visually",
"outline-style",
"overflow-anchor",
"overflow-block",

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

@ -10,18 +10,14 @@
#include "Layers.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/Document.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "mozilla/layers/APZPublicUtils.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/LayersMessageUtils.h"
#include "mozilla/layers/PAPZ.h"
#include "mozilla/layers/RepaintRequest.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/StaticPrefs_layout.h"
#include "nsDeckFrame.h"
#include "nsIScrollableFrame.h"
#include "nsLayoutUtils.h"
#include "nsPlaceholderFrame.h"
@ -33,13 +29,9 @@
namespace mozilla {
using gfx::gfxVars;
using gfx::IntSize;
using layers::APZCCallbackHelper;
using layers::FrameMetrics;
using layers::LayerManager;
using layers::RepaintRequest;
using layers::ScrollableLayerGuid;
typedef ScrollableLayerGuid::ViewID ViewID;
@ -805,12 +797,11 @@ bool DisplayPortUtils::CalculateAndSetDisplayPortMargins(
aRepaintMode);
}
bool DisplayPortUtils::MaybeCreateDisplayPort(nsDisplayListBuilder* aBuilder,
nsIFrame* aScrollFrame,
RepaintMode aRepaintMode) {
bool DisplayPortUtils::MaybeCreateDisplayPort(
nsDisplayListBuilder* aBuilder, nsIFrame* aScrollFrame,
nsIScrollableFrame* aScrollFrameAsScrollable, RepaintMode aRepaintMode) {
nsIContent* content = aScrollFrame->GetContent();
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame);
if (!content || !scrollableFrame) {
if (!content) {
return false;
}
@ -823,7 +814,7 @@ bool DisplayPortUtils::MaybeCreateDisplayPort(nsDisplayListBuilder* aBuilder,
if (aBuilder->IsPaintingToWindow() &&
nsLayoutUtils::AsyncPanZoomEnabled(aScrollFrame) &&
!aBuilder->HaveScrollableDisplayPort() &&
scrollableFrame->WantAsyncScroll()) {
aScrollFrameAsScrollable->WantAsyncScroll()) {
// If we don't already have a displayport, calculate and set one.
if (!haveDisplayPort) {
// We only use the viewId for logging purposes, but create it
@ -835,7 +826,7 @@ bool DisplayPortUtils::MaybeCreateDisplayPort(nsDisplayListBuilder* aBuilder,
sDisplayportLog, LogLevel::Debug,
("Setting DP on first-encountered scrollId=%" PRIu64 "\n", viewId));
CalculateAndSetDisplayPortMargins(scrollableFrame, aRepaintMode);
CalculateAndSetDisplayPortMargins(aScrollFrameAsScrollable, aRepaintMode);
#ifdef DEBUG
haveDisplayPort = HasNonMinimalDisplayPort(content);
MOZ_ASSERT(haveDisplayPort,
@ -884,10 +875,8 @@ bool DisplayPortUtils::MaybeCreateDisplayPortInFirstScrollFrameEncountered(
aFrame->GetContent()->GetID() == nsGkAtoms::tabbrowser_arrowscrollbox) {
return false;
}
nsIScrollableFrame* sf = do_QueryFrame(aFrame);
if (sf) {
if (MaybeCreateDisplayPort(aBuilder, aFrame, RepaintMode::Repaint)) {
if (nsIScrollableFrame* sf = do_QueryFrame(aFrame)) {
if (MaybeCreateDisplayPort(aBuilder, aFrame, sf, RepaintMode::Repaint)) {
return true;
}
}
@ -901,28 +890,21 @@ bool DisplayPortUtils::MaybeCreateDisplayPortInFirstScrollFrameEncountered(
if (aFrame->IsSubDocumentFrame()) {
PresShell* presShell = static_cast<nsSubDocumentFrame*>(aFrame)
->GetSubdocumentPresShellForPainting(0);
nsIFrame* root = presShell ? presShell->GetRootFrame() : nullptr;
if (root) {
if (nsIFrame* root = presShell ? presShell->GetRootFrame() : nullptr) {
if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(root, aBuilder)) {
return true;
}
}
}
if (aFrame->IsDeckFrame()) {
// only descend the visible card of a decks
nsIFrame* child = static_cast<nsDeckFrame*>(aFrame)->GetSelectedBox();
if (child) {
return MaybeCreateDisplayPortInFirstScrollFrameEncountered(child,
aBuilder);
}
if (aFrame->StyleUIReset()->mMozSubtreeHiddenOnlyVisually) {
// Only descend the visible card of deck / tabpanels
return false;
}
for (nsIFrame* child : aFrame->PrincipalChildList()) {
if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(child, aBuilder)) {
return true;
}
}
return false;
}

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

@ -278,9 +278,9 @@ class DisplayPortUtils {
* Returns true if there is a displayport on an async scrollable scrollframe
* after this call, either because one was just added or it already existed.
*/
static bool MaybeCreateDisplayPort(nsDisplayListBuilder* aBuilder,
nsIFrame* aScrollFrame,
RepaintMode aRepaintMode);
static bool MaybeCreateDisplayPort(
nsDisplayListBuilder* aBuilder, nsIFrame* aScrollFrame,
nsIScrollableFrame* aScrollFrameAsScrollable, RepaintMode aRepaintMode);
/**
* Sets a zero margin display port on all proper ancestors of aFrame that

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

@ -3961,38 +3961,24 @@ void PresShell::ClearMouseCaptureOnView(nsView* aView) {
}
void PresShell::ClearMouseCapture() {
nsIContent* capturingContent = GetCapturingContent();
if (!capturingContent) {
AllowMouseCapture(false);
return;
}
ReleaseCapturingContent();
AllowMouseCapture(false);
}
void PresShell::ClearMouseCapture(nsIFrame* aFrame) {
MOZ_ASSERT(
aFrame && aFrame->GetParent() &&
aFrame->GetParent()->Type() == LayoutFrameType::Deck,
"This function should only be called with a child frame of <deck>");
MOZ_ASSERT(aFrame);
nsIContent* capturingContent = GetCapturingContent();
if (!capturingContent) {
AllowMouseCapture(false);
return;
}
nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
if (!capturingFrame) {
ReleaseCapturingContent();
AllowMouseCapture(false);
return;
}
if (nsLayoutUtils::IsAncestorFrameCrossDocInProcess(aFrame, capturingFrame)) {
ReleaseCapturingContent();
AllowMouseCapture(false);
const bool shouldClear =
!capturingFrame ||
nsLayoutUtils::IsAncestorFrameCrossDocInProcess(aFrame, capturingFrame);
if (shouldClear) {
ClearMouseCapture();
}
}

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

@ -205,13 +205,22 @@ class PresShell final : public nsStubDocumentObserver,
static void ClearMouseCaptureOnView(nsView* aView);
// If a frame in the subtree rooted at aFrame is capturing the mouse then
// clears that capture.
static void ClearMouseCapture(nsIFrame* aFrame);
// Clear the capture content if it exists in this process.
static void ClearMouseCapture();
// If a frame in the subtree rooted at aFrame is capturing the mouse then
// clears that capture.
//
// NOTE(emilio): This is needed only so that mouse events captured by a remote
// frame don't remain being captured by the frame while hidden, see
// dom/events/test/browser_mouse_enterleave_switch_tab.js, which is the only
// test that meaningfully exercises this code path.
//
// We could consider maybe removing this, since the capturing content gets
// reset on mouse/pointerdown? Or maybe exposing an API so that the front-end
// does this.
static void ClearMouseCapture(nsIFrame* aFrame);
#ifdef ACCESSIBILITY
/**
* Return the document accessible for this PresShell if there is one.

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

@ -2624,7 +2624,7 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoPostTraversalFlags)
// flags for kids.
static ServoPostTraversalFlags SendA11yNotifications(
nsPresContext* aPresContext, Element* aElement,
ComputedStyle* aOldComputedStyle, ComputedStyle* aNewComputedStyle,
const ComputedStyle& aOldStyle, const ComputedStyle& aNewStyle,
ServoPostTraversalFlags aFlags) {
using Flags = ServoPostTraversalFlags;
MOZ_ASSERT(!(aFlags & Flags::SkipA11yNotifications) ||
@ -2638,13 +2638,24 @@ static ServoPostTraversalFlags SendA11yNotifications(
// enabled. Just skip everything.
return Flags::Empty;
}
if (aNewStyle.StyleUIReset()->mMozSubtreeHiddenOnlyVisually !=
aOldStyle.StyleUIReset()->mMozSubtreeHiddenOnlyVisually) {
if (aElement->GetParent() &&
aElement->GetParent()->IsXULElement(nsGkAtoms::tabpanels)) {
accService->NotifyOfTabPanelVisibilityChange(
aPresContext->PresShell(), aElement,
aNewStyle.StyleUIReset()->mMozSubtreeHiddenOnlyVisually);
}
}
if (aFlags & Flags::SkipA11yNotifications) {
// Propogate the skipping flag to descendants.
// Propagate the skipping flag to descendants.
return Flags::SkipA11yNotifications;
}
bool needsNotify = false;
bool isVisible = aNewComputedStyle->StyleVisibility()->IsVisible();
bool isVisible = aNewStyle.StyleVisibility()->IsVisible();
if (aFlags & Flags::SendA11yNotificationsIfShown) {
if (!isVisible) {
// Propagate the sending-if-shown flag to descendants.
@ -2657,7 +2668,7 @@ static ServoPostTraversalFlags SendA11yNotifications(
} else {
// If we shouldn't skip in any case, we need to check whether our
// own visibility has changed.
bool wasVisible = aOldComputedStyle->StyleVisibility()->IsVisible();
bool wasVisible = aOldStyle.StyleVisibility()->IsVisible();
needsNotify = wasVisible != isVisible;
}
@ -2887,9 +2898,9 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement,
AddLayerChangesForAnimation(styleFrame, primaryFrame, aElement, changeHint,
aRestyleState.ChangeList());
childrenFlags |=
SendA11yNotifications(mPresContext, aElement, oldOrDisplayContentsStyle,
upToDateStyle, aFlags);
childrenFlags |= SendA11yNotifications(mPresContext, aElement,
*oldOrDisplayContentsStyle,
*upToDateStyle, aFlags);
}
const bool traverseElementChildren =

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

@ -1,10 +0,0 @@
<html><body>
<object style="display:-moz-deck;">
<noscript>
</noscript>
</object>
</body></html>

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

@ -58,16 +58,13 @@ window.location.reload();
<s style=" display: -moz-box; position: absolute; direction: ltr;">
<q style=" display: table; direction: ltr;">
<bdo style=" display: block;">mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
<q style=" display: -moz-deck; position: absolute; direction: rtl;">mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
</q>
</bdo>
</q>
</s>
<map style=" display: inline-table; position: fixed; direction: ltr;">
<q style=" display: table; direction: ltr;">
<bdo style=" display: block;">
<q style=" display: -moz-deck; position: absolute; direction: rtl;">mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
</q>mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
<q style=" display: inline; direction: ltr;">mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
</q>
</bdo>
@ -366,7 +363,6 @@ window.location.reload();
</q>
</q>
</q>
<listing style=" display: -moz-deck; direction: ltr;">
<p style=" display: block; position: fixed; direction: ltr;">
<q style=" display: table-header-group; ">
<q style=" display: table-cell; ">
@ -405,7 +401,6 @@ window.location.reload();
</q>
</q>
</p>
</listing>
<q style=" display: table-header-group; ">
<q style=" display: table-cell; ">
<q style=" display: table; direction: ltr;">
@ -656,7 +651,7 @@ window.location.reload();
</map>
<ol style="display: inline-block;direction: ltr;">
<p style="display: inherit;position: fixed;direction: ltr;">
<body style="display: -moz-deck;position: absolute;direction: ltr;">mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
<body style="display: position: absolute;direction: ltr;">mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
</ol>mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
</html>mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m
</map>mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m mm m

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

@ -1,4 +0,0 @@
<!DOCTYPE html>
<html>
<body><div style="display: -moz-deck;"><div style="overflow: auto; border: 4294967296px solid blue;">M</div></div></body>
</html>

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

@ -105,7 +105,6 @@ load 343540-1.html
load 344057-1.xhtml
load 344064-1.html
load 344300-1.html
load 344300-2.html
load chrome://reftest/content/crashtests/layout/base/crashtests/344340-1.xhtml
load 347898-1.html
load 348126-1.html
@ -316,7 +315,6 @@ load 543648-1.html
load 560447-1.html
load 564063-1.html
load 569018-1.html
load chrome://reftest/content/crashtests/layout/base/crashtests/570038-1.html
load chrome://reftest/content/crashtests/layout/base/crashtests/572003.xhtml
load 572582-1.xhtml
load 576649-1.html

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

@ -215,8 +215,6 @@ nsContainerFrame* NS_NewRootBoxFrame(PresShell* aPresShell,
nsContainerFrame* NS_NewDocElementBoxFrame(PresShell* aPresShell,
ComputedStyle* aStyle);
nsIFrame* NS_NewDeckFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame* NS_NewLeafBoxFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame* NS_NewRangeFrame(PresShell* aPresShell, ComputedStyle* aStyle);
@ -4549,11 +4547,6 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay,
FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby));
return &data;
}
case StyleDisplayInside::MozDeck: {
static constexpr FrameConstructionData data =
SIMPLE_XUL_FCDATA(NS_NewDeckFrame);
return &data;
}
case StyleDisplayInside::MozPopup: {
static constexpr FrameConstructionData data(
NS_NewMenuPopupFrame, FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_IS_POPUP |

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

@ -117,7 +117,6 @@
#include "nsCSSPseudoElements.h"
#include "nsCSSRendering.h"
#include "nsTHashMap.h"
#include "nsDeckFrame.h"
#include "nsDisplayList.h"
#include "nsFlexContainerFrame.h"
#include "nsFontInflationData.h"

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

@ -35,7 +35,6 @@
#include "nsRepeatService.h"
#include "nsFloatManager.h"
#include "nsSprocketLayout.h"
#include "nsStackLayout.h"
#include "nsTextControlFrame.h"
#include "txMozillaXSLTProcessor.h"
#include "nsTreeSanitizer.h"
@ -329,7 +328,6 @@ void nsLayoutStatics::Shutdown() {
nsColorNames::ReleaseTable();
nsCSSProps::ReleaseTable();
nsRepeatService::Shutdown();
nsStackLayout::Shutdown();
nsXULContentUtils::Finish();
nsXULPrototypeCache::ReleaseGlobals();

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

@ -1,16 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<body style="direction: rtl;">
<form style="display: -moz-deck; width: 1em;">
<fieldset>
<legend>Your name</legend>
<input type="text" name="name" size="20"/>
</fieldset>
<fieldset>
<legend>Your E-mail address</legend>
<input type="text" name="email" size="25"/>
</fieldset>
</form>
</body>
</html>

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

@ -20,7 +20,6 @@ load 370703-1.html
load 370940-1.html
load 370967.html
load 378369.html
load 378413-1.xhtml
load 380116-1.xhtml
load 382610-1.html
load 383887-1.html

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

@ -22,7 +22,6 @@ FRAME_CLASSES = [
Frame("nsComboboxDisplayFrame", "ComboboxDisplay", NOT_LEAF),
Frame("nsContinuingTextFrame", "Text", LEAF),
Frame("nsDateTimeControlFrame", "DateTimeControl", NOT_LEAF),
Frame("nsDeckFrame", "Deck", NOT_LEAF),
Frame("nsDocElementBoxFrame", "DocElementBox", NOT_LEAF),
Frame("nsFieldSetFrame", "FieldSet", NOT_LEAF),
Frame("nsFileControlFrame", "Block", LEAF),

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

@ -1,14 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<table style="display: -moz-deck;"><tbody><tr><td>
<span style="position: relative;"><marquee><marquee><span style="position: absolute;">X</span></marquee></marquee></span>
</td></tr></tbody></table>
</body>
</html>

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

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<div style="display:-moz-deck">
<div>
<span style="float: right; width: 0;">x</span>
</div>
<div style="position: relative;">
<span style="float: right;">
<span style="position: absolute;">y</span>
</span>
</div>
</div>
</body>
</html>

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

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<style>
div { display: flex; }
div:after { display: -moz-deck; content: counter(b); }
</style>
</head>
<body>
<div></div>
</body>
</html>

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

@ -87,7 +87,6 @@ load 370174-2.html
load 370174-3.html
load 370699-1.html
load 370794-1.html
load 370866-1.xhtml
load 370884-1.xhtml
load 371348-1.xhtml
load 371561-1.html
@ -104,7 +103,6 @@ load 379217-2.xhtml
load 379917-1.xhtml
load 380012-1.html
load 381152-1.html
load 381786-1.html
load 382129-1.xhtml
load 382131-1.html
load 382199-1.html
@ -536,7 +534,6 @@ asserts(8-46) load 850931.html # nested multicols, inner multicol has column-wid
load 851396-1.html
load 854263-1.html
load 862185.html
load 862947-1.html
load 863935.html
load 866547-1.html
needs-focus pref(accessibility.browsewithcaret,true) load 868906.html

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

@ -100,7 +100,6 @@
#include "nsBlockFrame.h"
#include "nsDisplayList.h"
#include "nsChangeHint.h"
#include "nsDeckFrame.h"
#include "nsSubDocumentFrame.h"
#include "RetainedDisplayListBuilder.h"
@ -375,17 +374,19 @@ bool nsIFrame::IsVisibleConsideringAncestors(uint32_t aFlags) const {
const nsIFrame* frame = this;
while (frame) {
nsView* view = frame->GetView();
if (view && view->GetVisibility() == nsViewVisibility_kHide) return false;
if (this != frame && frame->HidesContent()) return false;
nsIFrame* parent = frame->GetParent();
nsDeckFrame* deck = do_QueryFrame(parent);
if (deck) {
if (deck->GetSelectedBox() != frame) return false;
if (view && view->GetVisibility() == nsViewVisibility_kHide) {
return false;
}
if (parent) {
if (frame->StyleUIReset()->mMozSubtreeHiddenOnlyVisually) {
return false;
}
if (this != frame && frame->HidesContent()) {
return false;
}
if (nsIFrame* parent = frame->GetParent()) {
frame = parent;
} else {
parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(frame);
@ -1286,6 +1287,10 @@ void nsIFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
scrollableFrame->PostPendingResnap();
}
}
if (StyleUIReset()->mMozSubtreeHiddenOnlyVisually &&
!aOldComputedStyle->StyleUIReset()->mMozSubtreeHiddenOnlyVisually) {
PresShell::ClearMouseCapture(this);
}
} else { // !aOldComputedStyle
handleStickyChange = disp->mPosition == StylePositionProperty::Sticky;
}
@ -3983,22 +3988,21 @@ static bool ShouldSkipFrame(nsDisplayListBuilder* aBuilder,
if (aBuilder->IsBackgroundOnly()) {
return true;
}
if (aBuilder->IsForGenerateGlyphMask() &&
(!aFrame->IsTextFrame() && aFrame->IsLeaf())) {
return true;
}
// The placeholder frame should have the same content as the OOF frame.
if (aBuilder->GetSelectedFramesOnly() &&
(aFrame->IsLeaf() && !aFrame->IsSelected())) {
return true;
}
static const nsFrameState skipFlags =
(NS_FRAME_TOO_DEEP_IN_FRAME_TREE | NS_FRAME_IS_NONDISPLAY);
return aFrame->HasAnyStateBits(skipFlags);
if (aFrame->HasAnyStateBits(skipFlags)) {
return true;
}
return aFrame->StyleUIReset()->mMozSubtreeHiddenOnlyVisually;
}
void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,

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

@ -1,8 +0,0 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div style="display: -moz-deck;" id="s">x</div>
</body>
</html>

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

@ -1,8 +0,0 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body onload="document.getElementById('s').firstChild.data = 'x';">
<div style="display: -moz-deck;" id="s"> </div>
</body>
</html>

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

@ -926,7 +926,6 @@ fuzzy-if(winWidget,0-123,0-1900) fuzzy-if(swgl,0-1,0-39) == 409659-1d.html 40965
== 410621-1.html 410621-1-ref.html
== 411059-1.html 411059-1-ref.html
fuzzy-if(winWidget,46-129,652-770) == 411334-1.xml 411334-1-ref.xml
== 411367-3.html 411367-3-ref.html
== 411585-1.html 411585-1-ref.html
== 411585-2.html 411585-2-ref.html
fails == 411585-3.html 411585-3-ref.html # bug 426909

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

@ -113,7 +113,7 @@ fuzzy(0-4,0-2) == underline-select-1.html underline-select-1-ref.html
== vertical-mode-decorations-1.html vertical-mode-decorations-1-ref.html
fuzzy-if(Android,0-238,0-36) == vertical-mode-decorations-2.html vertical-mode-decorations-2-ref.html
!= 1415214.html 1415214-notref.html
HTTP(..) == skip-ink-multiline-position.html skip-ink-multiline-position-ref.html
fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) HTTP(..) == skip-ink-multiline-position.html skip-ink-multiline-position-ref.html # not reliable on Win7 (bug 1770273)
== skip-ink-vertical-align.html skip-ink-vertical-align-ref.html
!= skip-ink-vertical-align-2.html skip-ink-vertical-align-2-notref.html
fuzzy(0-94,0-4) == skip-ink-cjk-1.html skip-ink-cjk-1-ref.html

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

@ -607,6 +607,7 @@ cbindgen-types = [
{ gecko = "StyleFontStyle", servo = "crate::values::computed::font::FontStyle" },
{ gecko = "StyleFontWeight", servo = "crate::values::computed::font::FontWeight" },
{ gecko = "StyleFontStretch", servo = "crate::values::computed::font::FontStretch" },
{ gecko = "StyleBoolInteger", servo = "crate::values::computed::BoolInteger" },
]
mapped-generic-types = [

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

@ -91,8 +91,6 @@ enum class StyleDisplay : uint16_t {
StyleDisplayFrom(StyleDisplayOutside::Block, StyleDisplayInside::MozBox),
MozInlineBox =
StyleDisplayFrom(StyleDisplayOutside::Inline, StyleDisplayInside::MozBox),
MozDeck =
StyleDisplayFrom(StyleDisplayOutside::XUL, StyleDisplayInside::MozDeck),
MozPopup =
StyleDisplayFrom(StyleDisplayOutside::XUL, StyleDisplayInside::MozPopup),
};

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

@ -3213,7 +3213,8 @@ nsChangeHint nsStyleUI::CalcDifference(const nsStyleUI& aNewData) const {
nsStyleUIReset::nsStyleUIReset(const Document& aDocument)
: mUserSelect(StyleUserSelect::Auto),
mScrollbarWidth(StyleScrollbarWidth::Auto),
mMozForceBrokenImageIcon(0),
mMozForceBrokenImageIcon(false),
mMozSubtreeHiddenOnlyVisually(false),
mIMEMode(StyleImeMode::Auto),
mWindowDragging(StyleWindowDragging::Default),
mWindowShadow(StyleWindowShadow::Default),
@ -3250,6 +3251,7 @@ nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
: mUserSelect(aSource.mUserSelect),
mScrollbarWidth(aSource.mScrollbarWidth),
mMozForceBrokenImageIcon(aSource.mMozForceBrokenImageIcon),
mMozSubtreeHiddenOnlyVisually(aSource.mMozSubtreeHiddenOnlyVisually),
mIMEMode(aSource.mIMEMode),
mWindowDragging(aSource.mWindowDragging),
mWindowShadow(aSource.mWindowShadow),
@ -3287,6 +3289,9 @@ nsChangeHint nsStyleUIReset::CalcDifference(
if (mMozForceBrokenImageIcon != aNewData.mMozForceBrokenImageIcon) {
hint |= nsChangeHint_ReconstructFrame;
}
if (mMozSubtreeHiddenOnlyVisually != aNewData.mMozSubtreeHiddenOnlyVisually) {
hint |= nsChangeHint_RepaintFrame;
}
if (mScrollbarWidth != aNewData.mScrollbarWidth) {
// For scrollbar-width change, we need some special handling similar
// to overflow properties. Specifically, we may need to reconstruct

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

@ -1863,7 +1863,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset {
return mAnimations[aIndex % mAnimationTimelineCount].GetTimeline();
}
uint8_t mMozForceBrokenImageIcon; // (0 if not forcing, otherwise forcing)
mozilla::StyleBoolInteger mMozForceBrokenImageIcon;
mozilla::StyleBoolInteger mMozSubtreeHiddenOnlyVisually;
mozilla::StyleImeMode mIMEMode;
mozilla::StyleWindowDragging mWindowDragging;
mozilla::StyleWindowShadow mWindowShadow;

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

@ -104,6 +104,7 @@ const char* gInaccessibleProperties[] = {
"-moz-min-font-size-ratio", // parsed by UA sheets only
"-moz-box-layout", // chrome-only internal properties
"-moz-font-smoothing-background-color", // chrome-only internal properties
"-moz-subtree-hidden-only-visually", // chrome-only internal properties
"-moz-window-input-region-margin", // chrome-only internal properties
"-moz-window-opacity", // chrome-only internal properties
"-moz-window-transform", // chrome-only internal properties

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

@ -134,8 +134,6 @@ skip-if = true # Bug 701060
[test_bug418986-2.html]
[test_bug437915.html]
[test_bug450191.html]
[test_bug453896_deck.html]
support-files = bug453896_iframe.html
[test_bug470769.html]
[test_bug499655.html]
[test_bug499655.xhtml]

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

@ -1,42 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=453896
-->
<head>
<title>Test for Bug 453896</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="run()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=453896">Mozilla Bug 453896</a>
<div id="display">
<div style="display:-moz-deck; height: 300px; width: 300px;">
<iframe src="about:blank"></iframe>
<iframe id="subdoc" src="bug453896_iframe.html"></iframe>
<iframe src="about:blank"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 453896 **/
function run()
{
var iframe = document.getElementById("subdoc");
var subdoc = iframe.contentDocument;
var subwin = iframe.contentWindow;
subwin.run(window);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

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

@ -19,7 +19,6 @@ const NON_CONTENT_ACCESSIBLE_VALUES = {
"-moz-autofill-background",
],
"display": [
"-moz-deck",
"-moz-popup",
"-moz-box",
"-moz-inline-box",

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

@ -1,6 +0,0 @@
<html>
<head><title>Testcase bug 290743 - This display:-moz-deck testcase freezes Mozilla</title></head>
<body style="display:-moz-deck;">
<input type="radio"><input type="radio">
</body>
</html>

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

@ -1,12 +0,0 @@
<html><head>
</head>
<body>
<div style="display: -moz-deck"><div style="display: -moz-popup"></div></div>
<div style="position: relative">Y</div>
</body>
</html>

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

@ -1,5 +0,0 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<tabpanels>
<treechildren style="display: -moz-deck;"/>
</tabpanels>
</window>

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

@ -1,31 +0,0 @@
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menulist id="b" style="display: -moz-box;">
<panel id="c" style=" position: absolute;">
<popup onunderflow="document.getElementById('c').removeAttribute('style')"/>
</panel>
<menupopup id="a" style="display: -moz-box;">
<menulist/>
</menupopup>
<panel style="display: -moz-deck;" onoverflow="document.getElementById('b').removeAttribute('style')">
<popup style="display: -moz-deck;"/>
</panel>
</menulist>
<script id="script" xmlns="http://www.w3.org/1999/xhtml"><![CDATA[
function doe() {
document.getElementById('c').removeAttribute('style');
document.documentElement.clientHeight;
document.getElementById('b').removeAttribute('style');
document.getElementById('a').setAttribute('selected', 'true');
document.getElementById('a').setAttribute('style', 'position: fixed;');
document.documentElement.clientHeight;
document.getElementById('a').removeAttribute('style');
}
function doe2() {
window.location.reload();
}
setTimeout(doe2, 200);
setTimeout(doe,100);
]]></script>
</window>

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

@ -5,12 +5,10 @@ load chrome://reftest/content/crashtests/layout/xul/crashtests/151826-1.xhtml
load chrome://reftest/content/crashtests/layout/xul/crashtests/168724-1.xhtml
load chrome://reftest/content/crashtests/layout/xul/crashtests/189814-1.xhtml
skip-if(Android) load chrome://reftest/content/crashtests/layout/xul/crashtests/289410-1.xhtml
load 290743.html
load chrome://reftest/content/crashtests/layout/xul/crashtests/291702-1.xhtml
load chrome://reftest/content/crashtests/layout/xul/crashtests/291702-2.xhtml
load chrome://reftest/content/crashtests/layout/xul/crashtests/291702-3.xhtml
load chrome://reftest/content/crashtests/layout/xul/crashtests/294371-1.xhtml
load 311457-1.html
load chrome://reftest/content/crashtests/layout/xul/crashtests/322786-1.xhtml
skip-if(Android) load chrome://reftest/content/crashtests/layout/xul/crashtests/325377.xhtml
skip-if(Android) load chrome://reftest/content/crashtests/layout/xul/crashtests/326879-1.xhtml
@ -24,7 +22,6 @@ load chrome://reftest/content/crashtests/layout/xul/crashtests/366112-1.xhtml
skip-if(Android) load chrome://reftest/content/crashtests/layout/xul/crashtests/366203-1.xhtml
load 367185-1.xhtml
load 369942-1.xhtml
skip-if(Android) load chrome://reftest/content/crashtests/layout/xul/crashtests/374102-1.xhtml
load 376137-1.html
load 376137-2.html
load 377592-1.svg
@ -39,7 +36,6 @@ load 384871-1.html
load chrome://reftest/content/crashtests/layout/xul/crashtests/386642.xhtml
load chrome://reftest/content/crashtests/layout/xul/crashtests/387080-1.xhtml
load 391974-1.html
skip-if(Android) load chrome://reftest/content/crashtests/layout/xul/crashtests/399013.xhtml
load 402912-1.xhtml
load 404192.xhtml
load chrome://reftest/content/crashtests/layout/xul/crashtests/408904-1.xhtml

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

@ -23,7 +23,6 @@ UNIFIED_SOURCES += [
"nsBoxFrame.cpp",
"nsBoxLayout.cpp",
"nsBoxLayoutState.cpp",
"nsDeckFrame.cpp",
"nsDocElementBoxFrame.cpp",
"nsImageBoxFrame.cpp",
"nsLeafBoxFrame.cpp",
@ -39,7 +38,6 @@ UNIFIED_SOURCES += [
"nsSliderFrame.cpp",
"nsSplitterFrame.cpp",
"nsSprocketLayout.cpp",
"nsStackLayout.cpp",
"nsTextBoxFrame.cpp",
"nsXULPopupManager.cpp",
"nsXULTooltipListener.cpp",

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

@ -308,8 +308,7 @@ nsresult nsIFrame::SyncXULLayout(nsBoxLayoutState& aBoxLayoutState) {
nsresult nsIFrame::XULRedraw(nsBoxLayoutState& aState) {
if (aState.PaintingDisabled()) return NS_OK;
// nsStackLayout, at least, expects us to repaint descendants even
// if a damage rect is provided
// Unclear whether we could get away with just InvalidateFrame().
InvalidateFrameSubtree();
return NS_OK;

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

@ -1,283 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
//
// Eric Vaughan
// Netscape Communications
//
// See documentation in associated header file
//
#include "nsDeckFrame.h"
#include "mozilla/ComputedStyle.h"
#include "mozilla/PresShell.h"
#include "nsLayoutUtils.h"
#include "nsPresContext.h"
#include "nsIContent.h"
#include "nsCOMPtr.h"
#include "nsNameSpaceManager.h"
#include "nsGkAtoms.h"
#include "nsHTMLParts.h"
#include "nsCSSRendering.h"
#include "nsViewManager.h"
#include "nsBoxLayoutState.h"
#include "nsStackLayout.h"
#include "nsDisplayList.h"
#include "nsContainerFrame.h"
#include "nsContentUtils.h"
#include "nsXULPopupManager.h"
#include "nsImageBoxFrame.h"
#include "nsImageFrame.h"
#ifdef ACCESSIBILITY
# include "nsAccessibilityService.h"
#endif
using namespace mozilla;
nsIFrame* NS_NewDeckFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
return new (aPresShell) nsDeckFrame(aStyle, aPresShell->GetPresContext());
}
NS_IMPL_FRAMEARENA_HELPERS(nsDeckFrame)
NS_QUERYFRAME_HEAD(nsDeckFrame)
NS_QUERYFRAME_ENTRY(nsDeckFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
nsDeckFrame::nsDeckFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
: nsBoxFrame(aStyle, aPresContext, kClassID) {
nsCOMPtr<nsBoxLayout> layout;
NS_NewStackLayout(layout);
SetXULLayoutManager(layout);
}
nsresult nsDeckFrame::AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
int32_t aModType) {
nsresult rv =
nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
// if the index changed hide the old element and make the new element visible
if (aAttribute == nsGkAtoms::selectedIndex) {
IndexChanged();
}
return rv;
}
void nsDeckFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) {
nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
mIndex = GetSelectedIndex();
}
void nsDeckFrame::ShowBox(nsIFrame* aBox) { Animate(aBox, true); }
void nsDeckFrame::HideBox(nsIFrame* aBox) {
PresShell::ClearMouseCapture(aBox);
Animate(aBox, false);
}
void nsDeckFrame::IndexChanged() {
// did the index change?
int32_t index = GetSelectedIndex();
if (index == mIndex) return;
// redraw
InvalidateFrame();
// hide the currently showing box
nsIFrame* currentBox = GetSelectedBox();
if (currentBox) // only hide if it exists
HideBox(currentBox);
mSelectedBoxCache = nullptr;
mIndex = index;
ShowBox(GetSelectedBox());
#ifdef ACCESSIBILITY
nsAccessibilityService* accService = GetAccService();
if (accService) {
accService->DeckPanelSwitched(PresContext()->GetPresShell(), mContent,
currentBox, GetSelectedBox());
}
#endif
// Force any popups that might be anchored on elements within hidden
// box to update.
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && currentBox) {
pm->UpdatePopupPositions(currentBox->PresContext()->RefreshDriver());
}
}
int32_t nsDeckFrame::GetSelectedIndex() {
// default index is 0
int32_t index = 0;
// get the index attribute
nsAutoString value;
if (mContent->AsElement()->GetAttr(kNameSpaceID_None,
nsGkAtoms::selectedIndex, value)) {
nsresult error;
// convert it to an integer
index = value.ToInteger(&error);
}
return index;
}
nsIFrame* nsDeckFrame::GetSelectedBox() {
if (!mSelectedBoxCache && mIndex >= 0) {
mSelectedBoxCache = (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nullptr;
}
return mSelectedBoxCache;
}
void nsDeckFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) {
// if a tab is hidden all its children are too.
if (StyleVisibility()->mVisible == StyleVisibility::Hidden) {
return;
}
nsBoxFrame::BuildDisplayList(aBuilder, aLists);
}
void nsDeckFrame::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) {
nsIFrame* currentFrame = GetSelectedBox();
if (aOldFrame == currentFrame) {
mSelectedBoxCache = nullptr;
}
if (currentFrame && aOldFrame && currentFrame != aOldFrame) {
// If the frame we're removing is at an index that's less
// than mIndex, that means we're going to be shifting indexes
// by 1.
//
// We attempt to keep the same child displayed by automatically
// updating our internal notion of the current index.
int32_t removedIndex = mFrames.IndexOf(aOldFrame);
MOZ_ASSERT(removedIndex >= 0,
"A deck child was removed that was not in mFrames.");
if (removedIndex < mIndex) {
// This shouldn't invalidate our cache, but be really paranoid, it's not
// that important to keep our cache here.
mSelectedBoxCache = nullptr;
mIndex--;
// This is going to cause us to handle the index change in IndexedChanged,
// but since the new index will match mIndex, it's essentially a noop.
nsContentUtils::AddScriptRunner(new nsSetAttrRunnable(
mContent->AsElement(), nsGkAtoms::selectedIndex, mIndex));
}
}
nsBoxFrame::RemoveFrame(aListID, aOldFrame);
}
void nsDeckFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) {
// only paint the selected box
nsIFrame* box = GetSelectedBox();
if (!box) return;
// Putting the child in the background list. This is a little weird but
// it matches what we were doing before.
nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
BuildDisplayListForChild(aBuilder, box, set);
}
void nsDeckFrame::Animate(nsIFrame* aParentBox, bool start) {
if (!aParentBox) return;
nsImageBoxFrame* imgBoxFrame = do_QueryFrame(aParentBox);
nsImageFrame* imgFrame = do_QueryFrame(aParentBox);
if (imgBoxFrame) {
if (start)
imgBoxFrame->RestartAnimation();
else
imgBoxFrame->StopAnimation();
}
if (imgFrame) {
if (start)
imgFrame->RestartAnimation();
else
imgFrame->StopAnimation();
}
for (const auto& childList : aParentBox->ChildLists()) {
for (nsIFrame* child : childList.mList) {
Animate(child, start);
}
}
}
NS_IMETHODIMP
nsDeckFrame::DoXULLayout(nsBoxLayoutState& aState) {
// Make sure we tweak the state so it does not resize our children.
// We will do that.
ReflowChildFlags oldFlags = aState.LayoutFlags();
aState.SetLayoutFlags(ReflowChildFlags::NoSizeView);
// do a normal layout
nsresult rv = nsBoxFrame::DoXULLayout(aState);
// <deck> and <tabpanels> other than our browser's tab shouldn't have any
// <browser> or <iframe> to avoid running into troubles with Fission.
MOZ_ASSERT(
(mContent->IsXULElement(nsGkAtoms::tabpanels) &&
mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
#ifdef MOZ_THUNDERBIRD
u"tabpanelcontainer"_ns,
#else
u"tabbrowser-tabpanels"_ns,
#endif
eCaseMatters)) ||
!HasPossiblyRemoteContents());
// run though each child. Hide all but the selected one
nsIFrame* box = nsIFrame::GetChildXULBox(this);
nscoord count = 0;
while (box) {
// make collapsed children not show up
if (count != mIndex) {
HideBox(box);
} else {
ShowBox(box);
}
box = GetNextXULBox(box);
count++;
}
aState.SetLayoutFlags(oldFlags);
return rv;
}
bool nsDeckFrame::HasPossiblyRemoteContents() const {
auto hasRemoteOrMayChangeRemoteNessAttribute =
[](dom::Element& aElement) -> bool {
return (aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::remote,
nsGkAtoms::_true, eCaseMatters) ||
aElement.HasAttribute(u"maychangeremoteness"_ns));
};
for (nsIContent* node = mContent; node; node = node->GetNextNode(mContent)) {
if ((node->IsXULElement(nsGkAtoms::browser) ||
node->IsHTMLElement(nsGkAtoms::iframe)) &&
hasRemoteOrMayChangeRemoteNessAttribute(*(node->AsElement()))) {
return true;
}
}
return false;
}

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

@ -1,78 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
/**
Eric D Vaughan
A frame that can have multiple children. Only one child may be displayed at
one time. So the can be flipped though like a deck of cards.
**/
#ifndef nsDeckFrame_h___
#define nsDeckFrame_h___
#include "mozilla/Attributes.h"
#include "nsBoxFrame.h"
namespace mozilla {
class PresShell;
} // namespace mozilla
class nsDeckFrame final : public nsBoxFrame {
public:
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(nsDeckFrame)
friend nsIFrame* NS_NewDeckFrame(mozilla::PresShell* aPresShell,
ComputedStyle* aStyle);
virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
int32_t aModType) override;
NS_IMETHOD DoXULLayout(nsBoxLayoutState& aState) override;
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override;
virtual void BuildDisplayListForChildren(
nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) override;
virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) override;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override {
return MakeFrameName(u"Deck"_ns, aResult);
}
#endif
explicit nsDeckFrame(ComputedStyle* aStyle, nsPresContext* aPresContext);
nsIFrame* GetSelectedBox();
// Returns whether this frame has any <browser> or <iframe> elements.
// Note that this function traverses down all descendants so this function
// should be used only in debug builds.
bool HasPossiblyRemoteContents() const;
protected:
void IndexChanged();
int32_t GetSelectedIndex();
void HideBox(nsIFrame* aBox);
void ShowBox(nsIFrame* aBox);
private:
int32_t mIndex = 0;
nsIFrame* mSelectedBoxCache = nullptr;
void Animate(nsIFrame*, bool);
}; // class nsDeckFrame
#endif

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

@ -15,7 +15,6 @@
#include "nsStyleConsts.h"
#include "nsGkAtoms.h"
#include "nsBoxFrame.h"
#include "nsStackLayout.h"
#include "nsIAnonymousContentCreator.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"

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

@ -9,7 +9,6 @@
#include "nsGkAtoms.h"
#include "nsBoxFrame.h"
#include "nsDisplayList.h"
#include "nsStackLayout.h"
#include "nsIPopupContainer.h"
#include "nsIContent.h"
#include "nsFrameManager.h"

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

@ -1,209 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
//
// Eric Vaughan
// Netscape Communications
//
// See documentation in associated header file
//
#include "nsStackLayout.h"
#include "nsCOMPtr.h"
#include "nsBoxLayoutState.h"
#include "nsBoxFrame.h"
#include "nsGkAtoms.h"
#include "nsIContent.h"
#include "nsNameSpaceManager.h"
using namespace mozilla;
nsBoxLayout* nsStackLayout::gInstance = nullptr;
nsresult NS_NewStackLayout(nsCOMPtr<nsBoxLayout>& aNewLayout) {
if (!nsStackLayout::gInstance) {
nsStackLayout::gInstance = new nsStackLayout();
NS_IF_ADDREF(nsStackLayout::gInstance);
}
// we have not instance variables so just return our static one.
aNewLayout = nsStackLayout::gInstance;
return NS_OK;
}
/*static*/
void nsStackLayout::Shutdown() { NS_IF_RELEASE(gInstance); }
nsStackLayout::nsStackLayout() = default;
/*
* Sizing: we are as wide as the widest child
* we are tall as the tallest child.
*/
nsSize nsStackLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
nsSize prefSize(0, 0);
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
while (child) {
nsSize pref = child->GetXULPrefSize(aState);
AddXULMargin(child, pref);
if (pref.width > prefSize.width) {
prefSize.width = pref.width;
}
if (pref.height > prefSize.height) {
prefSize.height = pref.height;
}
child = nsIFrame::GetNextXULBox(child);
}
AddXULBorderAndPadding(aBox, prefSize);
return prefSize;
}
nsSize nsStackLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
nsSize minSize(0, 0);
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
while (child) {
nsSize min = child->GetXULMinSize(aState);
AddXULMargin(child, min);
if (min.width > minSize.width) {
minSize.width = min.width;
}
if (min.height > minSize.height) {
minSize.height = min.height;
}
child = nsIFrame::GetNextXULBox(child);
}
AddXULBorderAndPadding(aBox, minSize);
return minSize;
}
nsSize nsStackLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) {
nsSize maxSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
while (child) {
nsSize min = child->GetXULMinSize(aState);
nsSize max = child->GetXULMaxSize(aState);
max = nsIFrame::XULBoundsCheckMinMax(min, max);
AddXULMargin(child, max);
if (max.width < maxSize.width) {
maxSize.width = max.width;
}
if (max.height < maxSize.height) {
maxSize.height = max.height;
}
child = nsIFrame::GetNextXULBox(child);
}
AddXULBorderAndPadding(aBox, maxSize);
return maxSize;
}
nscoord nsStackLayout::GetAscent(nsIFrame* aBox, nsBoxLayoutState& aState) {
nscoord vAscent = 0;
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
while (child) {
nscoord ascent = child->GetXULBoxAscent(aState);
nsMargin margin;
child->GetXULMargin(margin);
ascent += margin.top;
if (ascent > vAscent) vAscent = ascent;
child = nsIFrame::GetNextXULBox(child);
}
return vAscent;
}
NS_IMETHODIMP
nsStackLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) {
nsRect clientRect;
aBox->GetXULClientRect(clientRect);
bool grow;
do {
nsIFrame* child = nsIFrame::GetChildXULBox(aBox);
grow = false;
while (child) {
nsMargin margin;
child->GetXULMargin(margin);
nsRect childRect(clientRect);
childRect.Deflate(margin);
if (childRect.width < 0) childRect.width = 0;
if (childRect.height < 0) childRect.height = 0;
nsRect oldRect(child->GetRect());
bool sizeChanged = !oldRect.IsEqualEdges(childRect);
// only lay out dirty children or children whose sizes have changed
if (sizeChanged || child->IsSubtreeDirty()) {
// add in the child's margin
nsMargin margin;
child->GetXULMargin(margin);
// Now place the child.
child->SetXULBounds(aState, childRect);
// Flow the child.
child->XULLayout(aState);
// Get the child's new rect.
childRect = child->GetRect();
childRect.Inflate(margin);
// Did the child push back on us and get bigger?
if (childRect.width > clientRect.width) {
clientRect.width = childRect.width;
grow = true;
}
if (childRect.height > clientRect.height) {
clientRect.height = childRect.height;
grow = true;
}
}
child = nsIFrame::GetNextXULBox(child);
}
} while (grow);
// if some HTML inside us got bigger we need to force ourselves to
// get bigger
nsRect bounds(aBox->GetRect());
nsMargin bp;
aBox->GetXULBorderAndPadding(bp);
clientRect.Inflate(bp);
if (clientRect.width > bounds.width || clientRect.height > bounds.height) {
if (clientRect.width > bounds.width) bounds.width = clientRect.width;
if (clientRect.height > bounds.height) bounds.height = clientRect.height;
aBox->SetXULBounds(aState, bounds);
}
return NS_OK;
}

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

@ -1,48 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
/**
Eric D Vaughan
A frame that can have multiple children. Only one child may be displayed at
one time. So the can be flipped though like a deck of cards.
**/
#ifndef nsStackLayout_h___
#define nsStackLayout_h___
#include "mozilla/Attributes.h"
#include "nsBoxLayout.h"
#include "nsCOMPtr.h"
#include "nsCoord.h"
nsresult NS_NewStackLayout(nsCOMPtr<nsBoxLayout>& aNewLayout);
class nsStackLayout : public nsBoxLayout {
public:
friend nsresult NS_NewStackLayout(nsCOMPtr<nsBoxLayout>& aNewLayout);
static void Shutdown();
nsStackLayout();
NS_IMETHOD XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) override;
virtual nsSize GetXULPrefSize(nsIFrame* aBox,
nsBoxLayoutState& aBoxLayoutState) override;
virtual nsSize GetXULMinSize(nsIFrame* aBox,
nsBoxLayoutState& aBoxLayoutState) override;
virtual nsSize GetXULMaxSize(nsIFrame* aBox,
nsBoxLayoutState& aBoxLayoutState) override;
virtual nscoord GetAscent(nsIFrame* aBox,
nsBoxLayoutState& aBoxLayoutState) override;
private:
static nsBoxLayout* gInstance;
}; // class nsStackLayout
#endif

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

@ -487,7 +487,7 @@ class Longhand(Property):
"LineBreak",
"LineClamp",
"MasonryAutoFlow",
"MozForceBrokenImageIcon",
"BoolInteger",
"text::MozControlCharacterVisibility",
"MathDepth",
"MozScriptMinSize",

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

@ -108,11 +108,23 @@ ${helpers.predefined_type(
enabled_in="chrome",
)}
// Hack to allow chrome to hide stuff only visually (without hiding it from
// a11y).
${helpers.predefined_type(
"-moz-subtree-hidden-only-visually",
"BoolInteger",
"computed::BoolInteger::zero()",
engines="gecko",
animation_value_type="discrete",
spec="None (Nonstandard internal property)",
enabled_in="chrome",
)}
// TODO(emilio): Probably also should be hidden from content.
${helpers.predefined_type(
"-moz-force-broken-image-icon",
"MozForceBrokenImageIcon",
"computed::MozForceBrokenImageIcon::false_value()",
"BoolInteger",
"computed::BoolInteger::zero()",
engines="gecko",
animation_value_type="discrete",
spec="None (Nonstandard Firefox-only property)",

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

@ -97,7 +97,7 @@ pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
#[cfg(feature = "gecko")]
pub use self::ui::CursorImage;
pub use self::ui::{Cursor, MozForceBrokenImageIcon, UserSelect};
pub use self::ui::{Cursor, BoolInteger, UserSelect};
pub use super::specified::TextTransform;
pub use super::specified::ViewportVariant;
pub use super::specified::{BorderStyle, TextDecorationLine};

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

@ -10,7 +10,7 @@ use crate::values::computed::Number;
use crate::values::generics::ui as generics;
pub use crate::values::specified::ui::CursorKind;
pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect};
pub use crate::values::specified::ui::{BoolInteger, UserSelect};
/// A computed value for the `cursor` property.
pub type Cursor = generics::GenericCursor<CursorImage>;

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

@ -101,8 +101,6 @@ pub enum DisplayInside {
#[cfg(feature = "gecko")]
MozBox,
#[cfg(feature = "gecko")]
MozDeck,
#[cfg(feature = "gecko")]
MozPopup,
}
@ -216,8 +214,6 @@ impl Display {
#[cfg(feature = "gecko")]
pub const MozInlineBox: Self = Self::new(DisplayOutside::Inline, DisplayInside::MozBox);
#[cfg(feature = "gecko")]
pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck);
#[cfg(feature = "gecko")]
pub const MozPopup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozPopup);
/// Make a raw display value from <display-outside> and <display-inside> values.
@ -598,8 +594,6 @@ impl Parse for Display {
#[cfg(feature = "gecko")]
"-moz-inline-box" if moz_display_values_enabled(context) => Display::MozInlineBox,
#[cfg(feature = "gecko")]
"-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck,
#[cfg(feature = "gecko")]
"-moz-popup" if moz_display_values_enabled(context) => Display::MozPopup,
})
}

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

@ -97,7 +97,7 @@ pub use self::transform::{Rotate, Scale, Transform};
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
#[cfg(feature = "gecko")]
pub use self::ui::CursorImage;
pub use self::ui::{Cursor, MozForceBrokenImageIcon, UserSelect};
pub use self::ui::{Cursor, BoolInteger, UserSelect};
pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
#[cfg(feature = "gecko")]

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

@ -88,31 +88,32 @@ impl SpecifiedValueInfo for CursorImage {
ToResolvedValue,
ToShmem,
)]
pub struct MozForceBrokenImageIcon(pub bool);
#[repr(transparent)]
pub struct BoolInteger(pub bool);
impl MozForceBrokenImageIcon {
/// Return initial value of -moz-force-broken-image-icon which is false.
impl BoolInteger {
/// Returns 0
#[inline]
pub fn false_value() -> MozForceBrokenImageIcon {
MozForceBrokenImageIcon(false)
pub fn zero() -> Self {
Self(false)
}
}
impl Parse for MozForceBrokenImageIcon {
impl Parse for BoolInteger {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<MozForceBrokenImageIcon, ParseError<'i>> {
) -> Result<Self, ParseError<'i>> {
// We intentionally don't support calc values here.
match input.expect_integer()? {
0 => Ok(MozForceBrokenImageIcon(false)),
1 => Ok(MozForceBrokenImageIcon(true)),
0 => Ok(Self(false)),
1 => Ok(Self(true)),
_ => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
}
}
}
impl ToCss for MozForceBrokenImageIcon {
impl ToCss for BoolInteger {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
@ -121,22 +122,6 @@ impl ToCss for MozForceBrokenImageIcon {
}
}
impl From<u8> for MozForceBrokenImageIcon {
fn from(bits: u8) -> MozForceBrokenImageIcon {
MozForceBrokenImageIcon(bits == 1)
}
}
impl From<MozForceBrokenImageIcon> for u8 {
fn from(v: MozForceBrokenImageIcon) -> u8 {
if v.0 {
1
} else {
0
}
}
}
/// A specified value for `scrollbar-color` property
pub type ScrollbarColor = generics::ScrollbarColor<Color>;

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

@ -79,6 +79,7 @@ include = [
"BreakBetween",
"BreakWithin",
"BorderStyle",
"BoolInteger",
"OutlineStyle",
"CaptionSide",
"FontSizeAdjust",

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

@ -113,7 +113,7 @@
ok(deck instanceof MozXULElement, "instance of MozXULElement");
ok(XULElement.isInstance(deck), "instance of XULElement");
is(deck.id, "foo", "attribute set");
is(deck.selectedIndex, "0", "Custom Element is property attached");
is(deck.selectedIndex, 0, "Custom Element is property attached");
deck.remove();
info("Checking that whitespace text is removed but non-whitespace text isn't");

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

@ -5,14 +5,13 @@
XUL Widget Test for deck
-->
<window title="Deck Test"
onload="setTimeout(run_tests, 0);"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<deck id="deck1" style="padding-top: 5px; padding-bottom: 12px;">
<button id="d1b1" label="Button One"/>
<button id="d1b2" label="Button Two is larger" height="80" style="margin: 1px;"/>
<button id="d1b2" label="Button Two is larger" style="height: 80px; margin: 1px;"/>
</deck>
<deck id="deck2" selectedIndex="1">
<button id="d2b1" label="Button One"/>
@ -44,19 +43,15 @@
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
SimpleTest.waitForExplicitFinish();
function run_tests() {
add_task(async function run_tests() {
test_deck();
test_deck_child_removal();
SimpleTest.finish();
}
await test_deck_child_removal();
});
function test_deck()
{
var deck = $("deck1");
ok(deck.selectedIndex === '0', "deck one selectedIndex");
is(deck.selectedIndex, 0, "deck one selectedIndex");
// this size is the button height, 80, plus the button padding of 1px on each side,
// plus the deck's 5px top padding and the 12px bottom padding.
var rect = deck.getBoundingClientRect();
@ -66,47 +61,52 @@ function test_deck()
// change the selected page of the deck and ensure that the mouse click goes
// to the button on that page
deck.selectedIndex = 1;
ok(deck.selectedIndex === '1', "deck one selectedIndex after change");
is(deck.selectedIndex, 1, "deck one selectedIndex after change");
synthesizeMouseExpectEvent(deck, 9, 9, { }, $("d1b2"), "click", "mouse on deck one after change");
deck = $("deck2");
ok(deck.selectedIndex === '1', "deck two selectedIndex");
is(deck.selectedIndex, 1, "deck two selectedIndex");
synthesizeMouseExpectEvent(deck, 9, 9, { }, $("d2b2"), "click", "mouse on deck two");
}
function test_deck_child_removal()
async function test_deck_child_removal()
{
// Start with a simple case where we have two child nodes in a deck, with
// the second child (index 1) selected. Removing the first node should
// automatically set the selectedIndex at 0.
let deck = $("deck3");
let child = $("d3b1");
is(deck.selectedIndex, "1", "Should have the deck element at index 1 selected");
is(deck.selectedIndex, 1, "Should have the deck element at index 1 selected");
// Remove the child at the 0th index. The deck should automatically
// set the selectedIndex to "0".
child.remove();
is(deck.selectedIndex, "0", "Should have the deck element at index 0 selected");
await Promise.resolve();
is(deck.selectedIndex, 0, "Should have the deck element at index 0 selected");
// Now scale it up by using a deck with 7 child nodes, and remove the
// first three, making sure that the selectedIndex is decremented
// each time.
deck = $("deck4");
let expectedIndex = 5;
is(deck.selectedIndex, String(expectedIndex),
is(deck.selectedIndex, expectedIndex,
"Should have the deck element at index " + expectedIndex + " selected");
for (let i = 0; i < 3; ++i) {
deck.firstChild.remove();
expectedIndex--;
is(deck.selectedIndex, String(expectedIndex),
await Promise.resolve();
is(deck.selectedIndex, expectedIndex,
"Should have the deck element at index " + expectedIndex + " selected");
}
// Check that removing the currently selected node doesn't change
// behaviour.
deck.childNodes[expectedIndex].remove();
is(deck.selectedIndex, String(expectedIndex),
await Promise.resolve();
is(deck.selectedIndex, expectedIndex,
"The selectedIndex should not change when removing the node " +
"at the selected index.");
@ -114,14 +114,16 @@ function test_deck_child_removal()
// nodes at indexes greater than the selected node.
deck = $("deck5");
expectedIndex = 2;
is(deck.selectedIndex, String(expectedIndex),
await Promise.resolve();
is(deck.selectedIndex, expectedIndex,
"Should have the deck element at index " + expectedIndex + " selected");
// And then remove all of the nodes, starting from last to first, making
// sure that the selectedIndex does not change.
while (deck.lastChild) {
deck.lastChild.remove();
is(deck.selectedIndex, String(expectedIndex),
await Promise.resolve();
is(deck.selectedIndex, expectedIndex,
"Should have the deck element at index " + expectedIndex + " selected");
}
}

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

@ -7,40 +7,6 @@
// This is loaded into chrome windows with the subscript loader. Wrap in
// a block to prevent accidentally leaking globals onto `window`.
{
class MozDeck extends MozXULElement {
set selectedIndex(val) {
if (this.selectedIndex == val) {
return;
}
this.setAttribute("selectedIndex", val);
var event = document.createEvent("Events");
event.initEvent("select", true, true);
this.dispatchEvent(event);
}
get selectedIndex() {
return this.getAttribute("selectedIndex") || "0";
}
set selectedPanel(val) {
var selectedIndex = -1;
for (
var panel = val;
panel != null;
panel = panel.previousElementSibling
) {
++selectedIndex;
}
this.selectedIndex = selectedIndex;
}
get selectedPanel() {
return this.children[this.selectedIndex];
}
}
customElements.define("deck", MozDeck);
class MozDropmarker extends MozXULElement {
constructor() {
super();

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

@ -158,14 +158,107 @@
customElements.define("tabbox", MozTabbox);
class MozTabpanels extends MozXULElement {
class MozDeck extends MozXULElement {
get isAsync() {
return this.getAttribute("async") == "true";
}
connectedCallback() {
if (this.delayConnectedCallback()) {
return;
}
this._selectedPanel = null;
this._inAsyncOperation = false;
let selectCurrentIndex = () => {
// Try to select the new node if any.
let index = this.selectedIndex;
let oldPanel = this._selectedPanel;
this._selectedPanel = this.children.item(index) || null;
this.updateSelectedIndex(index, oldPanel);
};
this._mutationObserver = new MutationObserver(records => {
let anyRemovals = records.some(record => !!record.removedNodes.length);
if (anyRemovals) {
// Try to keep the current selected panel in-place first.
let index = Array.from(this.children).indexOf(this._selectedPanel);
if (index != -1) {
// Try to keep the same node selected.
this.setAttribute("selectedIndex", index);
}
}
// Select the current index if needed in case mutations have made that
// available where it wasn't before.
if (!this._inAsyncOperation) {
selectCurrentIndex();
}
});
this._mutationObserver.observe(this, {
childList: true,
});
selectCurrentIndex();
}
disconnectedCallback() {
this._mutationObserver?.disconnect();
this._mutationObserver = null;
}
updateSelectedIndex(
val,
oldPanel = this.querySelector(":scope > .deck-selected")
) {
this._inAsyncOperation = false;
if (oldPanel != this._selectedPanel) {
oldPanel?.classList.remove("deck-selected");
this._selectedPanel?.classList.add("deck-selected");
}
this.setAttribute("selectedIndex", val);
}
set selectedIndex(val) {
if (val < 0 || val >= this.children.length) {
return;
}
let oldPanel = this._selectedPanel;
this._selectedPanel = this.children[val];
this._inAsyncOperation = this.isAsync;
if (!this._inAsyncOperation) {
this.updateSelectedIndex(val, oldPanel);
}
if (this._selectedPanel != oldPanel) {
let event = document.createEvent("Events");
event.initEvent("select", true, true);
this.dispatchEvent(event);
}
}
get selectedIndex() {
let indexStr = this.getAttribute("selectedIndex");
return indexStr ? parseInt(indexStr) : 0;
}
set selectedPanel(val) {
this.selectedIndex = Array.from(this.children).indexOf(val);
}
get selectedPanel() {
return this._selectedPanel;
}
}
customElements.define("deck", MozDeck);
class MozTabpanels extends MozDeck {
constructor() {
super();
this._tabbox = null;
this._selectedPanel = this.children.item(this.selectedIndex);
}
get tabbox() {
@ -186,46 +279,6 @@
return (this._tabbox = parent);
}
set selectedIndex(val) {
if (val < 0 || val >= this.children.length) {
return;
}
let panel = this._selectedPanel;
this._selectedPanel = this.children[val];
if (this.getAttribute("async") != "true") {
this.setAttribute("selectedIndex", val);
}
if (this._selectedPanel != panel) {
let event = document.createEvent("Events");
event.initEvent("select", true, true);
this.dispatchEvent(event);
}
}
get selectedIndex() {
let indexStr = this.getAttribute("selectedIndex");
return indexStr ? parseInt(indexStr) : -1;
}
set selectedPanel(val) {
let selectedIndex = -1;
for (
let panel = val;
panel != null;
panel = panel.previousElementSibling
) {
++selectedIndex;
}
this.selectedIndex = selectedIndex;
}
get selectedPanel() {
return this._selectedPanel;
}
/**
* nsIDOMXULRelatedElement
*/
@ -527,24 +580,25 @@
set selectedIndex(val) {
var tab = this.getItemAtIndex(val);
if (tab) {
for (let otherTab of this.allTabs) {
if (otherTab != tab && otherTab.selected) {
otherTab._selected = false;
}
if (!tab) {
return;
}
for (let otherTab of this.allTabs) {
if (otherTab != tab && otherTab.selected) {
otherTab._selected = false;
}
tab._selected = true;
}
tab._selected = true;
this.setAttribute("value", tab.value);
this.setAttribute("value", tab.value);
let linkedPanel = this.getRelatedElement(tab);
if (linkedPanel) {
this.tabbox.setAttribute("selectedIndex", val);
let linkedPanel = this.getRelatedElement(tab);
if (linkedPanel) {
this.tabbox.setAttribute("selectedIndex", val);
// This will cause an onselect event to fire for the tabpanel
// element.
this.tabbox.tabpanels.selectedPanel = linkedPanel;
}
// This will cause an onselect event to fire for the tabpanel
// element.
this.tabbox.tabpanels.selectedPanel = linkedPanel;
}
}

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

@ -448,18 +448,34 @@ treechildren::-moz-tree-cell(ltr) {
direction: ltr !important;
}
/********** deck & stack *********/
/********** deck, tabpanels & stack *********/
deck {
display: -moz-deck;
tabpanels > *|*:not(:-moz-native-anonymous) {
/* tabpanels is special: we want to avoid displaying them, but we still want
* the hidden children to be accessible */
-moz-subtree-hidden-only-visually: 1;
}
deck > *|*:not(:-moz-native-anonymous) {
visibility: hidden;
}
tabpanels > .deck-selected,
deck > .deck-selected {
-moz-subtree-hidden-only-visually: 0;
visibility: inherit;
}
tabpanels,
deck,
stack {
display: grid;
position: relative;
}
/* We shouldn't style native anonymous children like scrollbars or what not */
/* We shouldn't style native anonymous children like scrollbars or what not. */
tabpanels > *|*:not(:-moz-native-anonymous),
deck > *|*:not(:-moz-native-anonymous),
stack > *|*:not(:-moz-native-anonymous) {
grid-area: 1 / 1;
z-index: 0;
@ -489,10 +505,6 @@ tab {
-moz-box-pack: center;
}
tabpanels {
display: -moz-deck;
}
/********** tooltip *********/
tooltip[titletip="true"] {

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

@ -26,6 +26,9 @@ tabs {
padding: 0 10px;
margin-bottom: -12px;
position: relative;
/* Needs to sort on top of the tabbox, which is a grid container (and thus
* causes pseudo stacking contexts to be created) */
z-index: 1;
}
tab {