summaryrefslogtreecommitdiffstats
path: root/layout/forms
diff options
context:
space:
mode:
Diffstat (limited to 'layout/forms')
-rw-r--r--layout/forms/HTMLSelectEventListener.cpp2
-rw-r--r--layout/forms/crashtests/crashtests.list2
-rw-r--r--layout/forms/moz.build1
-rw-r--r--layout/forms/nsButtonFrameRenderer.cpp471
-rw-r--r--layout/forms/nsButtonFrameRenderer.h83
-rw-r--r--layout/forms/nsComboboxControlFrame.cpp600
-rw-r--r--layout/forms/nsComboboxControlFrame.h128
-rw-r--r--layout/forms/nsFieldSetFrame.cpp10
-rw-r--r--layout/forms/nsGfxButtonControlFrame.cpp4
-rw-r--r--layout/forms/nsGfxButtonControlFrame.h23
-rw-r--r--layout/forms/nsHTMLButtonControlFrame.cpp175
-rw-r--r--layout/forms/nsHTMLButtonControlFrame.h15
-rw-r--r--layout/forms/nsNumberControlFrame.cpp25
-rw-r--r--layout/forms/test/test_bug536567_perwindowpb.html2
-rw-r--r--layout/forms/test/test_bug935876.html14
15 files changed, 302 insertions, 1253 deletions
diff --git a/layout/forms/HTMLSelectEventListener.cpp b/layout/forms/HTMLSelectEventListener.cpp
index 4f6b1e3561..8c74c57cc0 100644
--- a/layout/forms/HTMLSelectEventListener.cpp
+++ b/layout/forms/HTMLSelectEventListener.cpp
@@ -40,7 +40,7 @@ static bool IsOptionInteractivelySelectable(HTMLSelectElement& aSelect,
// options in a display: contents subtree interactively.
// test_select_key_navigation_bug1498769.html tests for this and should
// probably be changed (and this loop removed) or alternatively
- // SelectChild.jsm should be changed to match it.
+ // SelectChild.sys.mjs should be changed to match it.
for (Element* el = &aOption; el && el != &aSelect;
el = el->GetParentElement()) {
if (Servo_Element_IsDisplayContents(el)) {
diff --git a/layout/forms/crashtests/crashtests.list b/layout/forms/crashtests/crashtests.list
index da43270ba6..5bc0fa7746 100644
--- a/layout/forms/crashtests/crashtests.list
+++ b/layout/forms/crashtests/crashtests.list
@@ -68,7 +68,7 @@ load 1405830.html
load 1418477.html
load 1432853.html
asserts(1-4) load 1460787-1.html
-load 1464165-1.html
+asserts(1-4) load 1464165-1.html # Big sizes.
load 1471157.html
load 1488219.html
load 1600207.html
diff --git a/layout/forms/moz.build b/layout/forms/moz.build
index 838a17bf92..93ec0a430c 100644
--- a/layout/forms/moz.build
+++ b/layout/forms/moz.build
@@ -19,7 +19,6 @@ EXPORTS += [
UNIFIED_SOURCES += [
"HTMLSelectEventListener.cpp",
"ListMutationObserver.cpp",
- "nsButtonFrameRenderer.cpp",
"nsCheckboxRadioFrame.cpp",
"nsColorControlFrame.cpp",
"nsComboboxControlFrame.cpp",
diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp
deleted file mode 100644
index 598610cf72..0000000000
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ /dev/null
@@ -1,471 +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/. */
-#include "nsButtonFrameRenderer.h"
-#include "nsCSSRendering.h"
-#include "nsPresContext.h"
-#include "nsPresContextInlines.h"
-#include "nsGkAtoms.h"
-#include "nsCSSPseudoElements.h"
-#include "nsNameSpaceManager.h"
-#include "mozilla/ServoStyleSet.h"
-#include "mozilla/Unused.h"
-#include "nsDisplayList.h"
-#include "nsITheme.h"
-#include "nsIFrame.h"
-#include "mozilla/dom/Element.h"
-
-#include "gfxUtils.h"
-#include "mozilla/layers/RenderRootStateManager.h"
-
-using namespace mozilla;
-using namespace mozilla::image;
-using namespace mozilla::layers;
-
-namespace mozilla {
-class nsDisplayButtonBoxShadowOuter;
-class nsDisplayButtonBorder;
-class nsDisplayButtonForeground;
-} // namespace mozilla
-
-nsButtonFrameRenderer::nsButtonFrameRenderer() : mFrame(nullptr) {
- MOZ_COUNT_CTOR(nsButtonFrameRenderer);
-}
-
-nsButtonFrameRenderer::~nsButtonFrameRenderer() {
- MOZ_COUNT_DTOR(nsButtonFrameRenderer);
-}
-
-void nsButtonFrameRenderer::SetFrame(nsIFrame* aFrame,
- nsPresContext* aPresContext) {
- mFrame = aFrame;
- ReResolveStyles(aPresContext);
-}
-
-nsIFrame* nsButtonFrameRenderer::GetFrame() { return mFrame; }
-
-void nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool aNotify) {
- dom::Element* element = mFrame->GetContent()->AsElement();
- if (aDisabled)
- element->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, u""_ns, aNotify);
- else
- element->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, aNotify);
-}
-
-bool nsButtonFrameRenderer::isDisabled() {
- return mFrame->GetContent()->AsElement()->IsDisabled();
-}
-
-nsresult nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
- nsDisplayList* aBackground,
- nsDisplayList* aForeground) {
- if (!mFrame->StyleEffects()->mBoxShadow.IsEmpty()) {
- aBackground->AppendNewToTop<nsDisplayButtonBoxShadowOuter>(aBuilder,
- GetFrame());
- }
-
- nsRect buttonRect =
- mFrame->GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(mFrame);
-
- const AppendedBackgroundType result =
- nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
- aBuilder, mFrame, buttonRect, aBackground);
- if (result == AppendedBackgroundType::None) {
- aBuilder->BuildCompositorHitTestInfoIfNeeded(GetFrame(), aBackground);
- }
-
- aBackground->AppendNewToTop<nsDisplayButtonBorder>(aBuilder, GetFrame(),
- this);
-
- // Only display focus rings if we actually have them. Since at most one
- // button would normally display a focus ring, most buttons won't have them.
- if (mInnerFocusStyle && mInnerFocusStyle->StyleBorder()->HasBorder() &&
- mFrame->IsThemed() &&
- mFrame->PresContext()->Theme()->ThemeWantsButtonInnerFocusRing()) {
- aForeground->AppendNewToTop<nsDisplayButtonForeground>(aBuilder, GetFrame(),
- this);
- }
- return NS_OK;
-}
-
-void nsButtonFrameRenderer::GetButtonInnerFocusRect(const nsRect& aRect,
- nsRect& aResult) {
- aResult = aRect;
- aResult.Deflate(mFrame->GetUsedBorderAndPadding());
-
- if (mInnerFocusStyle) {
- nsMargin innerFocusPadding(0, 0, 0, 0);
- mInnerFocusStyle->StylePadding()->GetPadding(innerFocusPadding);
-
- nsMargin framePadding = mFrame->GetUsedPadding();
-
- innerFocusPadding.top = std::min(innerFocusPadding.top, framePadding.top);
- innerFocusPadding.right =
- std::min(innerFocusPadding.right, framePadding.right);
- innerFocusPadding.bottom =
- std::min(innerFocusPadding.bottom, framePadding.bottom);
- innerFocusPadding.left =
- std::min(innerFocusPadding.left, framePadding.left);
-
- aResult.Inflate(innerFocusPadding);
- }
-}
-
-ImgDrawResult nsButtonFrameRenderer::PaintInnerFocusBorder(
- nsDisplayListBuilder* aBuilder, nsPresContext* aPresContext,
- gfxContext& aRenderingContext, const nsRect& aDirtyRect,
- const nsRect& aRect) {
- // we draw the -moz-focus-inner border just inside the button's
- // normal border and padding, to match Windows themes.
-
- nsRect rect;
-
- PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
- ? PaintBorderFlags::SyncDecodeImages
- : PaintBorderFlags();
-
- ImgDrawResult result = ImgDrawResult::SUCCESS;
-
- if (mInnerFocusStyle) {
- GetButtonInnerFocusRect(aRect, rect);
-
- result &=
- nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
- aDirtyRect, rect, mInnerFocusStyle, flags);
- }
-
- return result;
-}
-
-Maybe<nsCSSBorderRenderer>
-nsButtonFrameRenderer::CreateInnerFocusBorderRenderer(
- nsDisplayListBuilder* aBuilder, nsPresContext* aPresContext,
- gfxContext* aRenderingContext, const nsRect& aDirtyRect,
- const nsRect& aRect, bool* aBorderIsEmpty) {
- if (mInnerFocusStyle) {
- nsRect rect;
- GetButtonInnerFocusRect(aRect, rect);
-
- gfx::DrawTarget* dt =
- aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
- return nsCSSRendering::CreateBorderRenderer(
- aPresContext, dt, mFrame, aDirtyRect, rect, mInnerFocusStyle,
- aBorderIsEmpty);
- }
-
- return Nothing();
-}
-
-ImgDrawResult nsButtonFrameRenderer::PaintBorder(nsDisplayListBuilder* aBuilder,
- nsPresContext* aPresContext,
- gfxContext& aRenderingContext,
- const nsRect& aDirtyRect,
- const nsRect& aRect) {
- // get the button rect this is inside the focus and outline rects
- nsRect buttonRect = aRect;
- ComputedStyle* context = mFrame->Style();
-
- PaintBorderFlags borderFlags = aBuilder->ShouldSyncDecodeImages()
- ? PaintBorderFlags::SyncDecodeImages
- : PaintBorderFlags();
-
- nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext, mFrame,
- buttonRect);
-
- ImgDrawResult result =
- nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
- aDirtyRect, buttonRect, context, borderFlags);
-
- return result;
-}
-
-/**
- * Call this when styles change
- */
-void nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext) {
- // get all the styles
- ServoStyleSet* styleSet = aPresContext->StyleSet();
-
- // get styles assigned to -moz-focus-inner (ie dotted border on Windows)
- mInnerFocusStyle = styleSet->ProbePseudoElementStyle(
- *mFrame->GetContent()->AsElement(), PseudoStyleType::mozFocusInner,
- nullptr, mFrame->Style());
-}
-
-ComputedStyle* nsButtonFrameRenderer::GetComputedStyle(int32_t aIndex) const {
- switch (aIndex) {
- case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
- return mInnerFocusStyle;
- default:
- return nullptr;
- }
-}
-
-void nsButtonFrameRenderer::SetComputedStyle(int32_t aIndex,
- ComputedStyle* aComputedStyle) {
- switch (aIndex) {
- case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
- mInnerFocusStyle = aComputedStyle;
- break;
- }
-}
-
-namespace mozilla {
-
-class nsDisplayButtonBoxShadowOuter : public nsPaintedDisplayItem {
- public:
- nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder* aBuilder,
- nsIFrame* aFrame)
- : nsPaintedDisplayItem(aBuilder, aFrame) {
- MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter);
- }
- MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayButtonBoxShadowOuter)
-
- virtual bool CreateWebRenderCommands(
- mozilla::wr::DisplayListBuilder& aBuilder,
- mozilla::wr::IpcResourceUpdateQueue& aResources,
- const StackingContextHelper& aSc,
- mozilla::layers::RenderRootStateManager* aManager,
- nsDisplayListBuilder* aDisplayListBuilder) override;
-
- bool CanBuildWebRenderDisplayItems();
-
- virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
- virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
- bool* aSnap) const override;
- NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
-};
-
-nsRect nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder,
- bool* aSnap) const {
- *aSnap = false;
- return mFrame->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
-}
-
-void nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
- gfxContext* aCtx) {
- nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
-
- nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
- frameRect, GetPaintRect(aBuilder, aCtx));
-}
-
-bool nsDisplayButtonBoxShadowOuter::CanBuildWebRenderDisplayItems() {
- // FIXME(emilio): Is this right? That doesn't make much sense.
- if (mFrame->StyleEffects()->mBoxShadow.IsEmpty()) {
- return false;
- }
-
- bool hasBorderRadius;
- bool nativeTheme =
- nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
-
- // We don't support native themed things yet like box shadows around
- // input buttons.
- return !nativeTheme;
-}
-
-bool nsDisplayButtonBoxShadowOuter::CreateWebRenderCommands(
- mozilla::wr::DisplayListBuilder& aBuilder,
- mozilla::wr::IpcResourceUpdateQueue& aResources,
- const StackingContextHelper& aSc,
- mozilla::layers::RenderRootStateManager* aManager,
- nsDisplayListBuilder* aDisplayListBuilder) {
- if (!CanBuildWebRenderDisplayItems()) {
- return false;
- }
- int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
- nsRect shadowRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
- LayoutDeviceRect deviceBox =
- LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel);
- wr::LayoutRect deviceBoxRect = wr::ToLayoutRect(deviceBox);
-
- bool dummy;
- LayoutDeviceRect clipRect = LayoutDeviceRect::FromAppUnits(
- GetBounds(aDisplayListBuilder, &dummy), appUnitsPerDevPixel);
- wr::LayoutRect deviceClipRect = wr::ToLayoutRect(clipRect);
-
- bool hasBorderRadius;
- Unused << nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
-
- LayoutDeviceSize zeroSize;
- wr::BorderRadius borderRadius =
- wr::ToBorderRadius(zeroSize, zeroSize, zeroSize, zeroSize);
- if (hasBorderRadius) {
- gfx::RectCornerRadii borderRadii;
- hasBorderRadius = nsCSSRendering::GetBorderRadii(shadowRect, shadowRect,
- mFrame, borderRadii);
- if (hasBorderRadius) {
- borderRadius = wr::ToBorderRadius(borderRadii);
- }
- }
-
- const Span<const StyleBoxShadow> shadows =
- mFrame->StyleEffects()->mBoxShadow.AsSpan();
- MOZ_ASSERT(!shadows.IsEmpty());
-
- for (const StyleBoxShadow& shadow : Reversed(shadows)) {
- if (shadow.inset) {
- continue;
- }
- float blurRadius =
- float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
- gfx::DeviceColor shadowColor =
- ToDeviceColor(nsCSSRendering::GetShadowColor(shadow.base, mFrame, 1.0));
-
- LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
- nsPoint(shadow.base.horizontal.ToAppUnits(),
- shadow.base.vertical.ToAppUnits()),
- appUnitsPerDevPixel);
-
- float spreadRadius =
- float(shadow.spread.ToAppUnits()) / float(appUnitsPerDevPixel);
-
- aBuilder.PushBoxShadow(deviceBoxRect, deviceClipRect, !BackfaceIsHidden(),
- deviceBoxRect, wr::ToLayoutVector2D(shadowOffset),
- wr::ToColorF(shadowColor), blurRadius, spreadRadius,
- borderRadius, wr::BoxShadowClipMode::Outset);
- }
- return true;
-}
-
-class nsDisplayButtonBorder final : public nsPaintedDisplayItem {
- public:
- nsDisplayButtonBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- nsButtonFrameRenderer* aRenderer)
- : nsPaintedDisplayItem(aBuilder, aFrame), mBFR(aRenderer) {
- MOZ_COUNT_CTOR(nsDisplayButtonBorder);
- }
- MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayButtonBorder)
-
- virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
- HitTestState* aState,
- nsTArray<nsIFrame*>* aOutFrames) override {
- aOutFrames->AppendElement(mFrame);
- }
- virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
- virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
- bool* aSnap) const override;
- virtual bool CreateWebRenderCommands(
- mozilla::wr::DisplayListBuilder& aBuilder,
- mozilla::wr::IpcResourceUpdateQueue& aResources,
- const StackingContextHelper& aSc,
- mozilla::layers::RenderRootStateManager* aManager,
- nsDisplayListBuilder* aDisplayListBuilder) override;
- NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
- private:
- nsButtonFrameRenderer* mBFR;
-};
-
-bool nsDisplayButtonBorder::CreateWebRenderCommands(
- mozilla::wr::DisplayListBuilder& aBuilder,
- mozilla::wr::IpcResourceUpdateQueue& aResources,
- const StackingContextHelper& aSc,
- mozilla::layers::RenderRootStateManager* aManager,
- nsDisplayListBuilder* aDisplayListBuilder) {
- // This is really a combination of paint box shadow inner +
- // paint border.
- aBuilder.StartGroup(this);
- const nsRect buttonRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
- bool snap;
- nsRect visible = GetBounds(aDisplayListBuilder, &snap);
- nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(
- aBuilder, aSc, visible, mFrame, buttonRect);
-
- bool borderIsEmpty = false;
- Maybe<nsCSSBorderRenderer> br = nsCSSRendering::CreateBorderRenderer(
- mFrame->PresContext(), nullptr, mFrame, nsRect(),
- nsRect(ToReferenceFrame(), mFrame->GetSize()), mFrame->Style(),
- &borderIsEmpty, mFrame->GetSkipSides());
- if (!br) {
- if (borderIsEmpty) {
- aBuilder.FinishGroup();
- } else {
- aBuilder.CancelGroup(true);
- }
-
- return borderIsEmpty;
- }
-
- br->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
- aBuilder.FinishGroup();
- return true;
-}
-
-void nsDisplayButtonBorder::Paint(nsDisplayListBuilder* aBuilder,
- gfxContext* aCtx) {
- NS_ASSERTION(mFrame, "No frame?");
- nsPresContext* pc = mFrame->PresContext();
- nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
-
- // draw the border and background inside the focus and outline borders
- Unused << mBFR->PaintBorder(aBuilder, pc, *aCtx, GetPaintRect(aBuilder, aCtx),
- r);
-}
-
-nsRect nsDisplayButtonBorder::GetBounds(nsDisplayListBuilder* aBuilder,
- bool* aSnap) const {
- *aSnap = false;
- return aBuilder->IsForEventDelivery()
- ? nsRect(ToReferenceFrame(), mFrame->GetSize())
- : mFrame->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
-}
-
-class nsDisplayButtonForeground final : public nsPaintedDisplayItem {
- public:
- nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
- nsButtonFrameRenderer* aRenderer)
- : nsPaintedDisplayItem(aBuilder, aFrame), mBFR(aRenderer) {
- MOZ_COUNT_CTOR(nsDisplayButtonForeground);
- }
- MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayButtonForeground)
-
- void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
- bool CreateWebRenderCommands(
- mozilla::wr::DisplayListBuilder& aBuilder,
- mozilla::wr::IpcResourceUpdateQueue& aResources,
- const StackingContextHelper& aSc,
- mozilla::layers::RenderRootStateManager* aManager,
- nsDisplayListBuilder* aDisplayListBuilder) override;
- NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
- private:
- nsButtonFrameRenderer* mBFR;
-};
-
-void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
- gfxContext* aCtx) {
- nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
-
- // Draw the -moz-focus-inner border
- Unused << mBFR->PaintInnerFocusBorder(aBuilder, mFrame->PresContext(), *aCtx,
- GetPaintRect(aBuilder, aCtx), r);
-}
-
-bool nsDisplayButtonForeground::CreateWebRenderCommands(
- mozilla::wr::DisplayListBuilder& aBuilder,
- mozilla::wr::IpcResourceUpdateQueue& aResources,
- const StackingContextHelper& aSc,
- mozilla::layers::RenderRootStateManager* aManager,
- nsDisplayListBuilder* aDisplayListBuilder) {
- Maybe<nsCSSBorderRenderer> br;
- bool borderIsEmpty = false;
- bool dummy;
- nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
- br = mBFR->CreateInnerFocusBorderRenderer(
- aDisplayListBuilder, mFrame->PresContext(), nullptr,
- GetBounds(aDisplayListBuilder, &dummy), r, &borderIsEmpty);
-
- if (!br) {
- return borderIsEmpty;
- }
-
- aBuilder.StartGroup(this);
- br->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
- aBuilder.FinishGroup();
-
- return true;
-}
-
-} // namespace mozilla
diff --git a/layout/forms/nsButtonFrameRenderer.h b/layout/forms/nsButtonFrameRenderer.h
deleted file mode 100644
index ea5a9cdea4..0000000000
--- a/layout/forms/nsButtonFrameRenderer.h
+++ /dev/null
@@ -1,83 +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/. */
-
-#ifndef nsButtonFrameRenderer_h___
-#define nsButtonFrameRenderer_h___
-
-#include "nsMargin.h"
-#include "nsCSSRenderingBorders.h"
-
-class gfxContext;
-class nsIFrame;
-class nsPresContext;
-struct nsRect;
-
-namespace mozilla {
-class nsDisplayList;
-class nsDisplayListBuilder;
-} // namespace mozilla
-
-#define NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX 0
-#define NS_BUTTON_RENDERER_LAST_CONTEXT_INDEX \
- NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX
-
-class nsButtonFrameRenderer {
- using nsDisplayList = mozilla::nsDisplayList;
- using nsDisplayListBuilder = mozilla::nsDisplayListBuilder;
-
- typedef mozilla::image::ImgDrawResult ImgDrawResult;
- typedef mozilla::ComputedStyle ComputedStyle;
-
- public:
- nsButtonFrameRenderer();
- ~nsButtonFrameRenderer();
-
- /**
- * Create display list items for the button
- */
- nsresult DisplayButton(nsDisplayListBuilder* aBuilder,
- nsDisplayList* aBackground,
- nsDisplayList* aForeground);
-
- ImgDrawResult PaintInnerFocusBorder(nsDisplayListBuilder* aBuilder,
- nsPresContext* aPresContext,
- gfxContext& aRenderingContext,
- const nsRect& aDirtyRect,
- const nsRect& aRect);
-
- mozilla::Maybe<nsCSSBorderRenderer> CreateInnerFocusBorderRenderer(
- nsDisplayListBuilder* aBuilder, nsPresContext* aPresContext,
- gfxContext* aRenderingContext, const nsRect& aDirtyRect,
- const nsRect& aRect, bool* aBorderIsEmpty);
-
- ImgDrawResult PaintBorder(nsDisplayListBuilder* aBuilder,
- nsPresContext* aPresContext,
- gfxContext& aRenderingContext,
- const nsRect& aDirtyRect, const nsRect& aRect);
-
- void SetFrame(nsIFrame* aFrame, nsPresContext* aPresContext);
-
- void SetDisabled(bool aDisabled, bool notify);
-
- bool isActive();
- bool isDisabled();
-
- void GetButtonInnerFocusRect(const nsRect& aRect, nsRect& aResult);
-
- ComputedStyle* GetComputedStyle(int32_t aIndex) const;
- void SetComputedStyle(int32_t aIndex, ComputedStyle* aComputedStyle);
- void ReResolveStyles(nsPresContext* aPresContext);
-
- nsIFrame* GetFrame();
-
- private:
- // cached style for optional inner focus outline (used on Windows).
- RefPtr<ComputedStyle> mInnerFocusStyle;
-
- nsIFrame* mFrame;
-};
-
-#endif
diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp
index a935e3c761..1d4ff15b4f 100644
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -8,25 +8,17 @@
#include "gfxContext.h"
#include "gfxUtils.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/gfx/PathHelpers.h"
#include "nsCOMPtr.h"
#include "nsDeviceContext.h"
#include "nsFocusManager.h"
-#include "nsCheckboxRadioFrame.h"
#include "nsGkAtoms.h"
-#include "nsCSSAnonBoxes.h"
#include "nsHTMLParts.h"
#include "nsIFormControl.h"
#include "nsILayoutHistoryState.h"
-#include "nsNameSpaceManager.h"
#include "nsListControlFrame.h"
#include "nsPIDOMWindow.h"
-#include "mozilla/PresState.h"
#include "nsView.h"
#include "nsViewManager.h"
-#include "nsIContentInlines.h"
-#include "nsIDOMEventListener.h"
#include "nsISelectControlFrame.h"
#include "nsContentUtils.h"
#include "mozilla/dom/Event.h"
@@ -48,12 +40,8 @@
#include "nsTextNode.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/LookAndFeel.h"
-#include "mozilla/MouseEvents.h"
#include "mozilla/PresShell.h"
#include "mozilla/PresShellInlines.h"
-#include "mozilla/Unused.h"
-#include "gfx2DGlue.h"
-#include "mozilla/widget/nsAutoRollup.h"
using namespace mozilla;
using namespace mozilla::gfx;
@@ -85,124 +73,17 @@ nsComboboxControlFrame* NS_NewComboboxControlFrame(PresShell* aPresShell,
NS_IMPL_FRAMEARENA_HELPERS(nsComboboxControlFrame)
-//-----------------------------------------------------------
-// Reflow Debugging Macros
-// These let us "see" how many reflow counts are happening
-//-----------------------------------------------------------
-#ifdef DO_REFLOW_COUNTER
-
-# define MAX_REFLOW_CNT 1024
-static int32_t gTotalReqs = 0;
-;
-static int32_t gTotalReflows = 0;
-;
-static int32_t gReflowControlCntRQ[MAX_REFLOW_CNT];
-static int32_t gReflowControlCnt[MAX_REFLOW_CNT];
-static int32_t gReflowInx = -1;
-
-# define REFLOW_COUNTER() \
- if (mReflowId > -1) gReflowControlCnt[mReflowId]++;
-
-# define REFLOW_COUNTER_REQUEST() \
- if (mReflowId > -1) gReflowControlCntRQ[mReflowId]++;
-
-# define REFLOW_COUNTER_DUMP(__desc) \
- if (mReflowId > -1) { \
- gTotalReqs += gReflowControlCntRQ[mReflowId]; \
- gTotalReflows += gReflowControlCnt[mReflowId]; \
- printf("** Id:%5d %s RF: %d RQ: %d %d/%d %5.2f\n", mReflowId, \
- (__desc), gReflowControlCnt[mReflowId], \
- gReflowControlCntRQ[mReflowId], gTotalReflows, gTotalReqs, \
- float(gTotalReflows) / float(gTotalReqs) * 100.0f); \
- }
-
-# define REFLOW_COUNTER_INIT() \
- if (gReflowInx < MAX_REFLOW_CNT) { \
- gReflowInx++; \
- mReflowId = gReflowInx; \
- gReflowControlCnt[mReflowId] = 0; \
- gReflowControlCntRQ[mReflowId] = 0; \
- } else { \
- mReflowId = -1; \
- }
-
-// reflow messages
-# define REFLOW_DEBUG_MSG(_msg1) printf((_msg1))
-# define REFLOW_DEBUG_MSG2(_msg1, _msg2) printf((_msg1), (_msg2))
-# define REFLOW_DEBUG_MSG3(_msg1, _msg2, _msg3) \
- printf((_msg1), (_msg2), (_msg3))
-# define REFLOW_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4) \
- printf((_msg1), (_msg2), (_msg3), (_msg4))
-
-#else //-------------
-
-# define REFLOW_COUNTER_REQUEST()
-# define REFLOW_COUNTER()
-# define REFLOW_COUNTER_DUMP(__desc)
-# define REFLOW_COUNTER_INIT()
-
-# define REFLOW_DEBUG_MSG(_msg)
-# define REFLOW_DEBUG_MSG2(_msg1, _msg2)
-# define REFLOW_DEBUG_MSG3(_msg1, _msg2, _msg3)
-# define REFLOW_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4)
-
-#endif
-
-//------------------------------------------
-// This is for being VERY noisy
-//------------------------------------------
-#ifdef DO_VERY_NOISY
-# define REFLOW_NOISY_MSG(_msg1) printf((_msg1))
-# define REFLOW_NOISY_MSG2(_msg1, _msg2) printf((_msg1), (_msg2))
-# define REFLOW_NOISY_MSG3(_msg1, _msg2, _msg3) \
- printf((_msg1), (_msg2), (_msg3))
-# define REFLOW_NOISY_MSG4(_msg1, _msg2, _msg3, _msg4) \
- printf((_msg1), (_msg2), (_msg3), (_msg4))
-#else
-# define REFLOW_NOISY_MSG(_msg)
-# define REFLOW_NOISY_MSG2(_msg1, _msg2)
-# define REFLOW_NOISY_MSG3(_msg1, _msg2, _msg3)
-# define REFLOW_NOISY_MSG4(_msg1, _msg2, _msg3, _msg4)
-#endif
-
-//------------------------------------------
-// Displays value in pixels or twips
-//------------------------------------------
-#ifdef DO_PIXELS
-# define PX(__v) __v / 15
-#else
-# define PX(__v) __v
-#endif
-
-//------------------------------------------------------
-//-- Done with macros
-//------------------------------------------------------
-
nsComboboxControlFrame::nsComboboxControlFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext)
- : nsBlockFrame(aStyle, aPresContext, kClassID),
- mDisplayFrame(nullptr),
- mButtonFrame(nullptr),
- mDisplayISize(0),
- mMaxDisplayISize(0),
- mRecentSelectedIndex(NS_SKIP_NOTIFY_INDEX),
- mDisplayedIndex(-1),
- mInRedisplayText(false),
- mIsOpenInParentProcess(false){REFLOW_COUNTER_INIT()}
-
- //--------------------------------------------------------------
- nsComboboxControlFrame::~nsComboboxControlFrame() {
- REFLOW_COUNTER_DUMP("nsCCF");
-}
+ : nsHTMLButtonControlFrame(aStyle, aPresContext, kClassID) {}
-//--------------------------------------------------------------
+nsComboboxControlFrame::~nsComboboxControlFrame() = default;
NS_QUERYFRAME_HEAD(nsComboboxControlFrame)
NS_QUERYFRAME_ENTRY(nsComboboxControlFrame)
- NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
NS_QUERYFRAME_ENTRY(nsISelectControlFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame)
#ifdef ACCESSIBILITY
a11y::AccType nsComboboxControlFrame::AccessibleType() {
@@ -210,66 +91,6 @@ a11y::AccType nsComboboxControlFrame::AccessibleType() {
}
#endif
-void nsComboboxControlFrame::SetFocus(bool aOn, bool aRepaint) {
- // This is needed on a temporary basis. It causes the focus
- // rect to be drawn. This is much faster than ReResolvingStyle
- // Bug 32920
- InvalidateFrame();
-}
-
-nsPoint nsComboboxControlFrame::GetCSSTransformTranslation() {
- nsIFrame* frame = this;
- bool is3DTransform = false;
- Matrix transform;
- while (frame) {
- nsIFrame* parent;
- Matrix4x4Flagged ctm = frame->GetTransformMatrix(
- ViewportType::Layout, RelativeTo{nullptr}, &parent);
- Matrix matrix;
- if (ctm.Is2D(&matrix)) {
- transform = transform * matrix;
- } else {
- is3DTransform = true;
- break;
- }
- frame = parent;
- }
- nsPoint translation;
- if (!is3DTransform && !transform.HasNonTranslation()) {
- nsPresContext* pc = PresContext();
- // To get the translation introduced only by transforms we subtract the
- // regular non-transform translation.
- nsRootPresContext* rootPC = pc->GetRootPresContext();
- if (rootPC) {
- int32_t apd = pc->AppUnitsPerDevPixel();
- translation.x = NSFloatPixelsToAppUnits(transform._31, apd);
- translation.y = NSFloatPixelsToAppUnits(transform._32, apd);
- translation -= GetOffsetToCrossDoc(rootPC->PresShell()->GetRootFrame());
- }
- }
- return translation;
-}
-
-//----------------------------------------------------------
-//
-//----------------------------------------------------------
-#ifdef DO_REFLOW_DEBUG
-static int myCounter = 0;
-
-static void printSize(char* aDesc, nscoord aSize) {
- printf(" %s: ", aDesc);
- if (aSize == NS_UNCONSTRAINEDSIZE) {
- printf("UC");
- } else {
- printf("%d", PX(aSize));
- }
-}
-#endif
-
-//-------------------------------------------------------------------
-//-- Main Reflow for the Combobox
-//-------------------------------------------------------------------
-
bool nsComboboxControlFrame::HasDropDownButton() const {
const nsStyleDisplay* disp = StyleDisplay();
// FIXME(emilio): Blink also shows this for menulist-button and such... Seems
@@ -357,7 +178,7 @@ nscoord nsComboboxControlFrame::GetIntrinsicISize(gfxContext* aRenderingContext,
return *containISize;
}
- nscoord displayISize = mDisplayFrame->IntrinsicISizeOffsets().padding;
+ nscoord displayISize = 0;
if (!containISize && !StyleContent()->mContent.IsNone()) {
displayISize += GetLongestOptionISize(aRenderingContext);
}
@@ -408,12 +229,6 @@ void nsComboboxControlFrame::Reflow(nsPresContext* aPresContext,
// 3) Default block size of button is block size of display area
// 4) Inline size of display area is whatever is left over from our
// inline size after allocating inline size for the button.
-
- if (!mDisplayFrame) {
- NS_ERROR("Why did the frame constructor allow this to happen? Fix it!!");
- return;
- }
-
// Make sure the displayed text is the same as the selected option,
// bug 297389.
mDisplayedIndex = Select().SelectedIndex();
@@ -427,53 +242,29 @@ void nsComboboxControlFrame::Reflow(nsPresContext* aPresContext,
// Check if the theme specifies a minimum size for the dropdown button
// first.
const nscoord buttonISize = DropDownButtonISize();
- const auto borderPadding = aReflowInput.ComputedLogicalBorderPadding(wm);
const auto padding = aReflowInput.ComputedLogicalPadding(wm);
- const auto border = borderPadding - padding;
+ // We ignore inline-end-padding (by adding it to our label box size) if we
+ // have a dropdown button, so that the button aligns with the end of the
+ // padding box.
mDisplayISize = aReflowInput.ComputedISize() - buttonISize;
- mMaxDisplayISize = mDisplayISize + padding.IEnd(wm);
-
- nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
-
- // The button should occupy the same space as a scrollbar, and its position
- // starts from the border edge.
- if (mButtonFrame) {
- LogicalRect buttonRect(wm);
- buttonRect.IStart(wm) = borderPadding.IStart(wm) + mMaxDisplayISize;
- buttonRect.BStart(wm) = border.BStart(wm);
-
- buttonRect.ISize(wm) = buttonISize;
- buttonRect.BSize(wm) = mDisplayFrame->BSize(wm) + padding.BStartEnd(wm);
-
- const nsSize containerSize = aDesiredSize.PhysicalSize();
- mButtonFrame->SetRect(buttonRect, containerSize);
+ if (buttonISize) {
+ mDisplayISize += padding.IEnd(wm);
}
- if (!aStatus.IsInlineBreakBefore() && !aStatus.IsFullyComplete()) {
- // This frame didn't fit inside a fragmentation container. Splitting
- // a nsComboboxControlFrame makes no sense, so we override the status here.
- aStatus.Reset();
- }
+ nsHTMLButtonControlFrame::Reflow(aPresContext, aDesiredSize, aReflowInput,
+ aStatus);
}
void nsComboboxControlFrame::Init(nsIContent* aContent,
nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) {
- nsBlockFrame::Init(aContent, aParent, aPrevInFlow);
+ nsHTMLButtonControlFrame::Init(aContent, aParent, aPrevInFlow);
mEventListener = new HTMLSelectEventListener(
Select(), HTMLSelectEventListener::SelectType::Combobox);
}
-#ifdef DEBUG_FRAME_DUMP
-nsresult nsComboboxControlFrame::GetFrameName(nsAString& aResult) const {
- return MakeFrameName(u"ComboboxControl"_ns, aResult);
-}
-#endif
-
-///////////////////////////////////////////////////////////////
-
nsresult nsComboboxControlFrame::RedisplaySelectedText() {
nsAutoScriptBlocker scriptBlocker;
mDisplayedIndex = Select().SelectedIndex();
@@ -494,16 +285,12 @@ nsresult nsComboboxControlFrame::RedisplayText() {
mDisplayedOptionTextOrPreview.Truncate();
}
- REFLOW_DEBUG_MSG2(
- "RedisplayText \"%s\"\n",
- NS_LossyConvertUTF16toASCII(mDisplayedOptionTextOrPreview).get());
-
// Send reflow command because the new text maybe larger
nsresult rv = NS_OK;
- if (mDisplayContent && !previousText.Equals(mDisplayedOptionTextOrPreview)) {
- // Don't call ActuallyDisplayText(true) directly here since that
- // could cause recursive frame construction. See bug 283117 and the comment
- // in HandleRedisplayTextEvent() below.
+ if (!previousText.Equals(mDisplayedOptionTextOrPreview)) {
+ // Don't call ActuallyDisplayText(true) directly here since that could cause
+ // recursive frame construction. See bug 283117 and the comment in
+ // HandleRedisplayTextEvent() below.
// Revoke outstanding events to avoid out-of-order events which could mean
// displaying the wrong text.
@@ -512,7 +299,6 @@ nsresult nsComboboxControlFrame::RedisplayText() {
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
"If we happen to run our redisplay event now, we might kill "
"ourselves!");
-
mRedisplayTextEvent = new RedisplayTextEvent(this);
nsContentUtils::AddScriptRunner(mRedisplayTextEvent.get());
}
@@ -520,59 +306,37 @@ nsresult nsComboboxControlFrame::RedisplayText() {
}
void nsComboboxControlFrame::HandleRedisplayTextEvent() {
- // First, make sure that the content model is up to date and we've
- // constructed the frames for all our content in the right places.
- // Otherwise they'll end up under the wrong insertion frame when we
- // ActuallyDisplayText, since that flushes out the content sink by
- // calling SetText on a DOM node with aNotify set to true. See bug
- // 289730.
+ // First, make sure that the content model is up to date and we've constructed
+ // the frames for all our content in the right places. Otherwise they'll end
+ // up under the wrong insertion frame when we ActuallyDisplayText, since that
+ // flushes out the content sink by calling SetText on a DOM node with aNotify
+ // set to true. See bug 289730.
AutoWeakFrame weakThis(this);
PresContext()->Document()->FlushPendingNotifications(
FlushType::ContentAndNotify);
- if (!weakThis.IsAlive()) return;
-
- // Redirect frame insertions during this method (see
- // GetContentInsertionFrame()) so that any reframing that the frame
- // constructor forces upon us is inserted into the correct parent
- // (mDisplayFrame). See bug 282607.
- MOZ_ASSERT(!mInRedisplayText, "Nested RedisplayText");
- mInRedisplayText = true;
- mRedisplayTextEvent.Forget();
-
- ActuallyDisplayText(true);
if (!weakThis.IsAlive()) {
return;
}
-
- // XXXbz This should perhaps be IntrinsicDirty::None. Check.
- PresShell()->FrameNeedsReflow(mDisplayFrame,
- IntrinsicDirty::FrameAncestorsAndDescendants,
- NS_FRAME_IS_DIRTY);
-
- mInRedisplayText = false;
+ mRedisplayTextEvent.Forget();
+ ActuallyDisplayText(true);
+ // Note: `this` might be dead here.
}
void nsComboboxControlFrame::ActuallyDisplayText(bool aNotify) {
- RefPtr<nsTextNode> displayContent = mDisplayContent;
- if (mDisplayedOptionTextOrPreview.IsEmpty()) {
- // Have to use a space character of some sort for line-block-size
- // calculations to be right. Also, the space character must be zero-width
- // in order for the the inline-size calculations to be consistent between
- // size-contained comboboxes vs. empty comboboxes.
- //
- // XXXdholbert Does this space need to be "non-breaking"? I'm not sure
- // if it matters, but we previously had a comment here (added in 2002)
- // saying "Have to use a non-breaking space for line-height calculations
- // to be right". So I'll stick with a non-breaking space for now...
- static const char16_t space = 0xFEFF;
- displayContent->SetText(&space, 1, aNotify);
- } else {
- displayContent->SetText(mDisplayedOptionTextOrPreview, aNotify);
- }
-}
-
-int32_t nsComboboxControlFrame::GetIndexOfDisplayArea() {
- return mDisplayedIndex;
+ RefPtr<dom::Text> displayContent = mDisplayLabel->GetFirstChild()->AsText();
+ // Have to use a space character of some sort for line-block-size calculations
+ // to be right. Also, the space character must be zero-width in order for the
+ // inline-size calculations to be consistent between size-contained comboboxes
+ // vs. empty comboboxes.
+ //
+ // XXXdholbert Does this space need to be "non-breaking"? I'm not sure if it
+ // matters, but we previously had a comment here (added in 2002) saying "Have
+ // to use a non-breaking space for line-height calculations to be right". So
+ // I'll stick with a non-breaking space for now...
+ displayContent->SetText(mDisplayedOptionTextOrPreview.IsEmpty()
+ ? u"\ufeff"_ns
+ : mDisplayedOptionTextOrPreview,
+ aNotify);
}
bool nsComboboxControlFrame::IsDroppedDown() const {
@@ -631,53 +395,19 @@ nsresult nsComboboxControlFrame::HandleEvent(nsPresContext* aPresContext,
return NS_OK;
}
- if (mContent->AsElement()->State().HasState(dom::ElementState::DISABLED)) {
- return NS_OK;
- }
-
- // If we have style that affects how we are selected, feed event down to
- // nsIFrame::HandleEvent so that selection takes place when appropriate.
- if (IsContentDisabled()) {
- return nsBlockFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
- }
- return NS_OK;
-}
-
-nsContainerFrame* nsComboboxControlFrame::GetContentInsertionFrame() {
- return mInRedisplayText ? mDisplayFrame : nullptr;
-}
-
-void nsComboboxControlFrame::AppendDirectlyOwnedAnonBoxes(
- nsTArray<OwnedAnonBox>& aResult) {
- aResult.AppendElement(OwnedAnonBox(mDisplayFrame));
+ return nsHTMLButtonControlFrame::HandleEvent(aPresContext, aEvent,
+ aEventStatus);
}
nsresult nsComboboxControlFrame::CreateAnonymousContent(
nsTArray<ContentInfo>& aElements) {
- // The frames used to display the combo box and the button used to popup the
- // dropdown list are created through anonymous content. The dropdown list is
- // not created through anonymous content because its frame is initialized
- // specifically for the drop-down case and it is placed a special list
- // referenced through NS_COMBO_FRAME_POPUP_LIST_INDEX to keep separate from
- // the layout of the display and button.
- //
- // Note: The value attribute of the display content is set when an item is
- // selected in the dropdown list. If the content specified below does not
- // honor the value attribute than nothing will be displayed.
-
- // For now the content that is created corresponds to two input buttons. It
- // would be better to create the tag as something other than input, but then
- // there isn't any way to create a button frame since it isn't possible to set
- // the display type in CSS2 to create a button frame.
-
- // create content used for display
- // nsAtom* tag = NS_Atomize("mozcombodisplay");
-
- // Add a child text content node for the label
+ dom::Document* doc = mContent->OwnerDoc();
+ mDisplayLabel = doc->CreateHTMLElement(nsGkAtoms::label);
- nsNodeInfoManager* nimgr = mContent->NodeInfo()->NodeInfoManager();
-
- mDisplayContent = new (nimgr) nsTextNode(nimgr);
+ {
+ RefPtr<nsTextNode> text = doc->CreateEmptyTextNode();
+ mDisplayLabel->AppendChildTo(text, false, IgnoreErrors());
+ }
// set the value of the text node
mDisplayedIndex = Select().SelectedIndex();
@@ -686,14 +416,17 @@ nsresult nsComboboxControlFrame::CreateAnonymousContent(
}
ActuallyDisplayText(false);
- aElements.AppendElement(mDisplayContent);
+ aElements.AppendElement(mDisplayLabel);
if (HasDropDownButton()) {
mButtonContent = mContent->OwnerDoc()->CreateHTMLElement(nsGkAtoms::button);
- if (!mButtonContent) {
- return NS_ERROR_OUT_OF_MEMORY;
+ {
+ // This gives the button a reasonable height. This could be done via CSS
+ // instead, but relative font units like 1lh don't play very well with our
+ // font inflation implementation, so we do it this way instead.
+ RefPtr<nsTextNode> text = doc->CreateTextNode(u"\ufeff"_ns);
+ mButtonContent->AppendChildTo(text, false, IgnoreErrors());
}
-
- // make someone to listen to the button.
+ // Make someone to listen to the button.
mButtonContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type, u"button"_ns,
false);
// Set tabindex="-1" so that the button is not tabbable
@@ -707,8 +440,8 @@ nsresult nsComboboxControlFrame::CreateAnonymousContent(
void nsComboboxControlFrame::AppendAnonymousContentTo(
nsTArray<nsIContent*>& aElements, uint32_t aFilter) {
- if (mDisplayContent) {
- aElements.AppendElement(mDisplayContent);
+ if (mDisplayLabel) {
+ aElements.AppendElement(mDisplayLabel);
}
if (mButtonContent) {
@@ -716,226 +449,66 @@ void nsComboboxControlFrame::AppendAnonymousContentTo(
}
}
-nsIContent* nsComboboxControlFrame::GetDisplayNode() const {
- return mDisplayContent;
-}
+namespace mozilla {
-// XXXbz this is a for-now hack. Now that display:inline-block works,
-// need to revisit this.
-class nsComboboxDisplayFrame final : public nsBlockFrame {
+class ComboboxLabelFrame final : public nsBlockFrame {
public:
- NS_DECL_FRAMEARENA_HELPERS(nsComboboxDisplayFrame)
-
- nsComboboxDisplayFrame(ComputedStyle* aStyle,
- nsComboboxControlFrame* aComboBox)
- : nsBlockFrame(aStyle, aComboBox->PresContext(), kClassID),
- mComboBox(aComboBox) {}
+ NS_DECL_QUERYFRAME
+ NS_DECL_FRAMEARENA_HELPERS(ComboboxLabelFrame)
#ifdef DEBUG_FRAME_DUMP
nsresult GetFrameName(nsAString& aResult) const final {
- return MakeFrameName(u"ComboboxDisplay"_ns, aResult);
+ return MakeFrameName(u"ComboboxLabel"_ns, aResult);
}
#endif
void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput, nsReflowStatus& aStatus) final;
- void BuildDisplayList(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists) final;
-
- protected:
- nsComboboxControlFrame* mComboBox;
+ public:
+ ComboboxLabelFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
+ : nsBlockFrame(aStyle, aPresContext, kClassID) {}
};
-NS_IMPL_FRAMEARENA_HELPERS(nsComboboxDisplayFrame)
+NS_QUERYFRAME_HEAD(ComboboxLabelFrame)
+ NS_QUERYFRAME_ENTRY(ComboboxLabelFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
+NS_IMPL_FRAMEARENA_HELPERS(ComboboxLabelFrame)
-void nsComboboxDisplayFrame::Reflow(nsPresContext* aPresContext,
- ReflowOutput& aDesiredSize,
- const ReflowInput& aReflowInput,
- nsReflowStatus& aStatus) {
+void ComboboxLabelFrame::Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus) {
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
- MOZ_ASSERT(aReflowInput.mParentReflowInput &&
- aReflowInput.mParentReflowInput->mFrame == mComboBox,
- "Combobox's frame tree is wrong!");
- ReflowInput state(aReflowInput);
- if (state.ComputedBSize() == NS_UNCONSTRAINEDSIZE) {
- state.SetLineHeight(state.mParentReflowInput->GetLineHeight());
- }
- const WritingMode wm = aReflowInput.GetWritingMode();
- const LogicalMargin bp = state.ComputedLogicalBorderPadding(wm);
- MOZ_ASSERT(bp.BStartEnd(wm) == 0,
- "We shouldn't have border and padding in the block axis in UA!");
- nscoord inlineBp = bp.IStartEnd(wm);
- nscoord computedISize = mComboBox->mDisplayISize - inlineBp;
-
- // Other UAs ignore padding in some (but not all) platforms for (themed only)
- // comboboxes. Instead of doing that, we prevent that padding if present from
- // clipping the display text, by enforcing the display text minimum size in
- // that situation.
- const bool shouldHonorMinISize =
- mComboBox->StyleDisplay()->EffectiveAppearance() ==
- StyleAppearance::Menulist;
- if (shouldHonorMinISize) {
- computedISize = std::max(state.ComputedMinISize(), computedISize);
- // Don't let this size go over mMaxDisplayISize, since that'd be
- // observable via clientWidth / scrollWidth.
- computedISize =
- std::min(computedISize, mComboBox->mMaxDisplayISize - inlineBp);
- }
+ const nsComboboxControlFrame* combobox =
+ do_QueryFrame(GetParent()->GetParent());
+ MOZ_ASSERT(combobox, "Combobox's frame tree is wrong!");
+ MOZ_ASSERT(aReflowInput.ComputedPhysicalBorderPadding() == nsMargin(),
+ "We shouldn't have border and padding in UA!");
- state.SetComputedISize(std::max(0, computedISize));
+ ReflowInput state(aReflowInput);
+ state.SetComputedISize(combobox->mDisplayISize);
nsBlockFrame::Reflow(aPresContext, aDesiredSize, state, aStatus);
aStatus.Reset(); // this type of frame can't be split
}
-void nsComboboxDisplayFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists) {
- nsDisplayListCollection set(aBuilder);
- nsBlockFrame::BuildDisplayList(aBuilder, set);
-
- // remove background items if parent frame is themed
- if (mComboBox->IsThemed()) {
- set.BorderBackground()->DeleteAll(aBuilder);
- }
-
- set.MoveTo(aLists);
-}
-
-nsIFrame* nsComboboxControlFrame::CreateFrameForDisplayNode() {
- MOZ_ASSERT(mDisplayContent);
-
- // Get PresShell
- mozilla::PresShell* ps = PresShell();
- ServoStyleSet* styleSet = ps->StyleSet();
-
- // create the ComputedStyle for the anonymous block frame and text frame
- RefPtr<ComputedStyle> computedStyle =
- styleSet->ResolveInheritingAnonymousBoxStyle(
- PseudoStyleType::mozDisplayComboboxControlFrame, mComputedStyle);
-
- RefPtr<ComputedStyle> textComputedStyle =
- styleSet->ResolveStyleForText(mDisplayContent, mComputedStyle);
-
- // Start by creating our anonymous block frame
- mDisplayFrame = new (ps) nsComboboxDisplayFrame(computedStyle, this);
- mDisplayFrame->Init(mContent, this, nullptr);
-
- // Create a text frame and put it inside the block frame
- nsIFrame* textFrame = NS_NewTextFrame(ps, textComputedStyle);
-
- // initialize the text frame
- textFrame->Init(mDisplayContent, mDisplayFrame, nullptr);
- mDisplayContent->SetPrimaryFrame(textFrame);
+} // namespace mozilla
- mDisplayFrame->SetInitialChildList(FrameChildListID::Principal,
- nsFrameList(textFrame, textFrame));
- return mDisplayFrame;
+nsIFrame* NS_NewComboboxLabelFrame(PresShell* aPresShell,
+ ComputedStyle* aStyle) {
+ return new (aPresShell)
+ ComboboxLabelFrame(aStyle, aPresShell->GetPresContext());
}
void nsComboboxControlFrame::Destroy(DestroyContext& aContext) {
// Revoke any pending RedisplayTextEvent
mRedisplayTextEvent.Revoke();
-
mEventListener->Detach();
- // Cleanup frames in popup child list
- aContext.AddAnonymousContent(mDisplayContent.forget());
+ aContext.AddAnonymousContent(mDisplayLabel.forget());
aContext.AddAnonymousContent(mButtonContent.forget());
- nsBlockFrame::Destroy(aContext);
-}
-
-const nsFrameList& nsComboboxControlFrame::GetChildList(
- ChildListID aListID) const {
- return nsBlockFrame::GetChildList(aListID);
-}
-
-void nsComboboxControlFrame::GetChildLists(nsTArray<ChildList>* aLists) const {
- nsBlockFrame::GetChildLists(aLists);
-}
-
-void nsComboboxControlFrame::SetInitialChildList(ChildListID aListID,
- nsFrameList&& aChildList) {
- for (nsIFrame* f : aChildList) {
- MOZ_ASSERT(f->GetParent() == this, "Unexpected parent");
- nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(f->GetContent());
- if (formControl &&
- formControl->ControlType() == FormControlType::ButtonButton) {
- mButtonFrame = f;
- break;
- }
- }
- nsBlockFrame::SetInitialChildList(aListID, std::move(aChildList));
-}
-
-namespace mozilla {
-
-class nsDisplayComboboxFocus : public nsPaintedDisplayItem {
- public:
- nsDisplayComboboxFocus(nsDisplayListBuilder* aBuilder,
- nsComboboxControlFrame* aFrame)
- : nsPaintedDisplayItem(aBuilder, aFrame) {
- MOZ_COUNT_CTOR(nsDisplayComboboxFocus);
- }
- MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayComboboxFocus)
-
- void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
- NS_DISPLAY_DECL_NAME("ComboboxFocus", TYPE_COMBOBOX_FOCUS)
-};
-
-void nsDisplayComboboxFocus::Paint(nsDisplayListBuilder* aBuilder,
- gfxContext* aCtx) {
- static_cast<nsComboboxControlFrame*>(mFrame)->PaintFocus(
- *aCtx->GetDrawTarget(), ToReferenceFrame());
-}
-
-} // namespace mozilla
-
-void nsComboboxControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists) {
- if (aBuilder->IsForEventDelivery()) {
- // Don't allow children to receive events.
- // REVIEW: following old GetFrameForPoint
- DisplayBorderBackgroundOutline(aBuilder, aLists);
- } else {
- // REVIEW: Our in-flow child frames are inline-level so they will paint in
- // our content list, so we don't need to mess with layers.
- nsBlockFrame::BuildDisplayList(aBuilder, aLists);
- }
-
- // draw a focus indicator only when focus rings should be drawn
- if (Select().State().HasState(dom::ElementState::FOCUSRING) && IsThemed() &&
- PresContext()->Theme()->ThemeWantsButtonInnerFocusRing()) {
- aLists.Content()->AppendNewToTop<nsDisplayComboboxFocus>(aBuilder, this);
- }
-
- DisplaySelectionOverlay(aBuilder, aLists.Content());
-}
-
-void nsComboboxControlFrame::PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt) {
- /* Do we need to do anything? */
- dom::ElementState state = mContent->AsElement()->State();
- if (state.HasState(dom::ElementState::DISABLED) ||
- !state.HasState(dom::ElementState::FOCUS)) {
- return;
- }
-
- int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
-
- nsRect clipRect = mDisplayFrame->GetRect() + aPt;
- aDrawTarget.PushClipRect(
- NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, aDrawTarget));
-
- StrokeOptions strokeOptions;
- nsLayoutUtils::InitDashPattern(strokeOptions, StyleBorderStyle::Dotted);
- ColorPattern color(ToDeviceColor(StyleText()->mColor));
- nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
- clipRect.width -= onePixel;
- clipRect.height -= onePixel;
- Rect r = ToRect(nsLayoutUtils::RectToGfxRect(clipRect, appUnitsPerDevPixel));
- StrokeSnappedEdgesOfRect(r, aDrawTarget, color, strokeOptions);
-
- aDrawTarget.PopClip();
+ nsHTMLButtonControlFrame::Destroy(aContext);
}
//---------------------------------------------------------
@@ -960,6 +533,7 @@ nsComboboxControlFrame::OnOptionSelected(int32_t aIndex, bool aSelected) {
void nsComboboxControlFrame::FireValueChangeEvent() {
// Fire ValueChange event to indicate data value of combo box has changed
+ // FIXME(emilio): This shouldn't be exposed to content.
nsContentUtils::AddScriptRunner(new AsyncEventDispatcher(
mContent, u"ValueChange"_ns, CanBubble::eYes, ChromeOnlyDispatch::eNo));
}
diff --git a/layout/forms/nsComboboxControlFrame.h b/layout/forms/nsComboboxControlFrame.h
index e878c0ebe3..4daa636f1a 100644
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -7,56 +7,30 @@
#ifndef nsComboboxControlFrame_h___
#define nsComboboxControlFrame_h___
-#ifdef DEBUG_evaughan
-// #define DEBUG_rods
-#endif
-
-#ifdef DEBUG_rods
-// #define DO_REFLOW_DEBUG
-// #define DO_REFLOW_COUNTER
-// #define DO_UNCONSTRAINED_CHECK
-// #define DO_PIXELS
-// #define DO_NEW_REFLOW
-#endif
-
-// Mark used to indicate when onchange has been fired for current combobox item
-#define NS_SKIP_NOTIFY_INDEX -2
-
#include "mozilla/Attributes.h"
-#include "nsBlockFrame.h"
#include "nsIFormControlFrame.h"
#include "nsIAnonymousContentCreator.h"
#include "nsISelectControlFrame.h"
#include "nsIRollupListener.h"
#include "nsThreadUtils.h"
-
-class nsComboboxDisplayFrame;
-class nsTextNode;
+#include "nsHTMLButtonControlFrame.h"
namespace mozilla {
class PresShell;
class HTMLSelectEventListener;
+class ComboboxLabelFrame;
namespace dom {
class HTMLSelectElement;
}
-
-namespace gfx {
-class DrawTarget;
-} // namespace gfx
} // namespace mozilla
-class nsComboboxControlFrame final : public nsBlockFrame,
- public nsIFormControlFrame,
+class nsComboboxControlFrame final : public nsHTMLButtonControlFrame,
public nsIAnonymousContentCreator,
public nsISelectControlFrame {
- using DrawTarget = mozilla::gfx::DrawTarget;
using Element = mozilla::dom::Element;
public:
- friend nsComboboxControlFrame* NS_NewComboboxControlFrame(
- mozilla::PresShell* aPresShell, ComputedStyle* aStyle);
- friend class nsComboboxDisplayFrame;
-
+ friend class mozilla::ComboboxLabelFrame;
explicit nsComboboxControlFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext);
~nsComboboxControlFrame();
@@ -69,17 +43,17 @@ class nsComboboxControlFrame final : public nsBlockFrame,
void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) final;
- nsIContent* GetDisplayNode() const;
- nsIFrame* CreateFrameForDisplayNode();
-
#ifdef ACCESSIBILITY
mozilla::a11y::AccType AccessibleType() final;
#endif
nscoord GetMinISize(gfxContext* aRenderingContext) final;
-
nscoord GetPrefISize(gfxContext* aRenderingContext) final;
+ // We're a leaf, so we need to report ourselves as the content insertion
+ // frame.
+ nsContainerFrame* GetContentInsertionFrame() override { return this; }
+
void Reflow(nsPresContext* aCX, ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput, nsReflowStatus& aStatus) final;
@@ -88,27 +62,15 @@ class nsComboboxControlFrame final : public nsBlockFrame,
mozilla::WidgetGUIEvent* aEvent,
nsEventStatus* aEventStatus) final;
- void BuildDisplayList(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists) final;
-
- void PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt);
-
void Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) final;
+ void Destroy(DestroyContext&) final;
#ifdef DEBUG_FRAME_DUMP
- nsresult GetFrameName(nsAString& aResult) const final;
+ nsresult GetFrameName(nsAString& aResult) const final {
+ return MakeFrameName(u"ComboboxControl"_ns, aResult);
+ }
#endif
- void Destroy(DestroyContext&) final;
-
- void SetInitialChildList(ChildListID aListID, nsFrameList&& aChildList) final;
- const nsFrameList& GetChildList(ChildListID aListID) const final;
- void GetChildLists(nsTArray<ChildList>* aLists) const final;
-
- nsContainerFrame* GetContentInsertionFrame() final;
-
- // Return the dropdown and display frame.
- void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) final;
// nsIFormControlFrame
nsresult SetFormProperty(nsAtom* aName, const nsAString& aValue) final {
@@ -116,32 +78,10 @@ class nsComboboxControlFrame final : public nsBlockFrame,
}
/**
- * Inform the control that it got (or lost) focus.
- * If it lost focus, the dropdown menu will be rolled up if needed,
- * and FireOnChange() will be called.
- * @param aOn true if got focus, false if lost focus.
- * @param aRepaint if true then force repaint (NOTE: we always force repaint
- * currently)
- * @note This method might destroy |this|.
- */
- MOZ_CAN_RUN_SCRIPT_BOUNDARY
- void SetFocus(bool aOn, bool aRepaint) final;
-
- /**
- * Return the available space before and after this frame for
- * placing the drop-down list, and the current 2D translation.
- * Note that either or both can be less than or equal to zero,
- * if both are then the drop-down should be closed.
- */
- void GetAvailableDropdownSpace(mozilla::WritingMode aWM, nscoord* aBefore,
- nscoord* aAfter,
- mozilla::LogicalPoint* aTranslation);
- int32_t GetIndexOfDisplayArea();
- /**
* @note This method might destroy |this|.
*/
+ void FireValueChangeEvent();
nsresult RedisplaySelectedText();
- int32_t UpdateRecentIndex(int32_t aIndex);
bool IsDroppedDown() const;
@@ -192,53 +132,23 @@ class nsComboboxControlFrame final : public nsBlockFrame,
nsComboboxControlFrame* mControlFrame;
};
- void CheckFireOnChange();
- void FireValueChangeEvent();
nsresult RedisplayText();
void HandleRedisplayTextEvent();
void ActuallyDisplayText(bool aNotify);
- // If our total transform to the root frame of the root document is only a 2d
- // translation then return that translation, otherwise returns (0,0).
- nsPoint GetCSSTransformTranslation();
-
mozilla::dom::HTMLSelectElement& Select() const;
void GetOptionText(uint32_t aIndex, nsAString& aText) const;
- RefPtr<nsTextNode> mDisplayContent; // Anonymous content used to display the
- // current selection
- RefPtr<Element> mButtonContent; // Anonymous content for the button
- nsContainerFrame* mDisplayFrame; // frame to display selection
- nsIFrame* mButtonFrame; // button frame
-
- // The inline size of our display area. Used by that frame's reflow
- // to size to the full inline size except the drop-marker.
- nscoord mDisplayISize;
- // The maximum inline size of our display area, which is the
- // nsComoboxControlFrame's border-box.
- //
- // Going over this would be observable via DOM APIs like client / scrollWidth.
- nscoord mMaxDisplayISize;
-
+ RefPtr<Element> mDisplayLabel; // Anonymous content for the label
+ RefPtr<Element> mButtonContent; // Anonymous content for the button
nsRevocableEventPtr<RedisplayTextEvent> mRedisplayTextEvent;
- int32_t mRecentSelectedIndex;
- int32_t mDisplayedIndex;
+ // The inline size of our display area. Used by that frame's reflow to size to
+ // the full inline size except the drop-marker.
+ nscoord mDisplayISize = 0;
+ int32_t mDisplayedIndex = -1;
nsString mDisplayedOptionTextOrPreview;
-
RefPtr<mozilla::HTMLSelectEventListener> mEventListener;
-
- // See comment in HandleRedisplayTextEvent().
- bool mInRedisplayText;
- bool mIsOpenInParentProcess;
-
- // static class data member for Bug 32920
- // only one control can be focused at a time
- static nsComboboxControlFrame* sFocused;
-
-#ifdef DO_REFLOW_COUNTER
- int32_t mReflowId;
-#endif
};
#endif
diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp
index 03781da8bd..c96b293e82 100644
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -785,11 +785,6 @@ void nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
void nsFieldSetFrame::SetInitialChildList(ChildListID aListID,
nsFrameList&& aChildList) {
nsContainerFrame::SetInitialChildList(aListID, std::move(aChildList));
- if (nsBlockFrame* legend = do_QueryFrame(GetLegend())) {
- // A rendered legend always establish a new formatting context.
- // https://html.spec.whatwg.org/multipage/rendering.html#rendered-legend
- legend->AddStateBits(NS_BLOCK_STATIC_BFC);
- }
MOZ_ASSERT(
aListID != FrameChildListID::Principal || GetInner() || GetLegend(),
"Setting principal child list should populate our inner frame "
@@ -816,11 +811,6 @@ void nsFieldSetFrame::InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
nsContainerFrame::InsertFrames(aListID, aPrevFrame, aPrevFrameLine,
std::move(aFrameList));
MOZ_ASSERT(GetLegend());
- if (nsBlockFrame* legend = do_QueryFrame(GetLegend())) {
- // A rendered legend always establish a new formatting context.
- // https://html.spec.whatwg.org/multipage/rendering.html#rendered-legend
- legend->AddStateBits(NS_BLOCK_STATIC_BFC);
- }
}
#ifdef DEBUG
diff --git a/layout/forms/nsGfxButtonControlFrame.cpp b/layout/forms/nsGfxButtonControlFrame.cpp
index 37aa996c27..b250030e13 100644
--- a/layout/forms/nsGfxButtonControlFrame.cpp
+++ b/layout/forms/nsGfxButtonControlFrame.cpp
@@ -160,10 +160,6 @@ nsresult nsGfxButtonControlFrame::AttributeChanged(int32_t aNameSpaceID,
return rv;
}
-nsContainerFrame* nsGfxButtonControlFrame::GetContentInsertionFrame() {
- return this;
-}
-
nsresult nsGfxButtonControlFrame::HandleEvent(nsPresContext* aPresContext,
WidgetGUIEvent* aEvent,
nsEventStatus* aEventStatus) {
diff --git a/layout/forms/nsGfxButtonControlFrame.h b/layout/forms/nsGfxButtonControlFrame.h
index 32d4689559..38c30590ab 100644
--- a/layout/forms/nsGfxButtonControlFrame.h
+++ b/layout/forms/nsGfxButtonControlFrame.h
@@ -7,9 +7,7 @@
#ifndef nsGfxButtonControlFrame_h___
#define nsGfxButtonControlFrame_h___
-#include "mozilla/Attributes.h"
#include "nsHTMLButtonControlFrame.h"
-#include "nsCOMPtr.h"
#include "nsIAnonymousContentCreator.h"
class nsTextNode;
@@ -29,26 +27,25 @@ class nsGfxButtonControlFrame final : public nsHTMLButtonControlFrame,
void Destroy(DestroyContext&) override;
- virtual nsresult HandleEvent(nsPresContext* aPresContext,
- mozilla::WidgetGUIEvent* aEvent,
- nsEventStatus* aEventStatus) override;
+ nsresult HandleEvent(nsPresContext* aPresContext,
+ mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus* aEventStatus) override;
#ifdef DEBUG_FRAME_DUMP
- virtual nsresult GetFrameName(nsAString& aResult) const override;
+ nsresult GetFrameName(nsAString& aResult) const override;
#endif
NS_DECL_QUERYFRAME
// nsIAnonymousContentCreator
- virtual nsresult CreateAnonymousContent(
- nsTArray<ContentInfo>& aElements) override;
- virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
- uint32_t aFilter) override;
+ nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
+ void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
+ uint32_t aFilter) override;
- virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
- int32_t aModType) override;
+ nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
+ int32_t aModType) override;
- virtual nsContainerFrame* GetContentInsertionFrame() override;
+ nsContainerFrame* GetContentInsertionFrame() override { return this; }
protected:
nsresult GetDefaultLabel(nsAString& aLabel) const;
diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp
index 7a599f093b..cb24ccbfb9 100644
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -10,15 +10,17 @@
#include "mozilla/PresShell.h"
#include "nsIFrameInlines.h"
#include "nsContainerFrame.h"
+#include "nsPresContextInlines.h"
#include "nsIFormControlFrame.h"
#include "nsPresContext.h"
#include "nsLayoutUtils.h"
#include "nsGkAtoms.h"
-#include "nsButtonFrameRenderer.h"
#include "nsDisplayList.h"
+#include "nsCSSRendering.h"
#include <algorithm>
using namespace mozilla;
+using namespace mozilla::image;
nsContainerFrame* NS_NewHTMLButtonControlFrame(PresShell* aPresShell,
ComputedStyle* aStyle) {
@@ -39,7 +41,13 @@ void nsHTMLButtonControlFrame::Init(nsIContent* aContent,
nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) {
nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
- mRenderer.SetFrame(this, PresContext());
+
+ // get all the styles
+ ServoStyleSet* styleSet = PresContext()->StyleSet();
+
+ // Get styles assigned to -moz-focus-inner (i.e. dotted border on Windows)
+ mInnerFocusStyle = styleSet->ProbePseudoElementStyle(
+ *mContent->AsElement(), PseudoStyleType::mozFocusInner, nullptr, Style());
}
NS_QUERYFRAME_HEAD(nsHTMLButtonControlFrame)
@@ -57,8 +65,8 @@ void nsHTMLButtonControlFrame::SetFocus(bool aOn, bool aRepaint) {}
nsresult nsHTMLButtonControlFrame::HandleEvent(nsPresContext* aPresContext,
WidgetGUIEvent* aEvent,
nsEventStatus* aEventStatus) {
- // if disabled do nothing
- if (mRenderer.isDisabled()) {
+ if (mContent->AsElement()->IsDisabled()) {
+ // If disabled do nothing
return NS_OK;
}
@@ -67,14 +75,125 @@ nsresult nsHTMLButtonControlFrame::HandleEvent(nsPresContext* aPresContext,
return nsIFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
}
-bool nsHTMLButtonControlFrame::ShouldClipPaintingToBorderBox() {
+bool nsHTMLButtonControlFrame::ShouldClipPaintingToBorderBox() const {
// FIXME(emilio): probably should account for per-axis clipping...
return StyleDisplay()->mOverflowX != StyleOverflow::Visible;
}
+namespace mozilla {
+
+class nsDisplayButtonForeground final : public nsPaintedDisplayItem {
+ public:
+ nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+ : nsPaintedDisplayItem(aBuilder, aFrame) {
+ MOZ_COUNT_CTOR(nsDisplayButtonForeground);
+ }
+ MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayButtonForeground)
+
+ void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+ bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) override;
+ NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
+};
+
+void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
+ gfxContext* aCtx) {
+ static_cast<nsHTMLButtonControlFrame*>(mFrame)->PaintInnerFocusBorder(
+ aBuilder, *aCtx, GetPaintRect(aBuilder, aCtx),
+ nsRect(ToReferenceFrame(), mFrame->GetSize()));
+}
+
+bool nsDisplayButtonForeground::CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::wr::IpcResourceUpdateQueue& aResources,
+ const StackingContextHelper& aSc,
+ mozilla::layers::RenderRootStateManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) {
+ bool borderIsEmpty = false;
+ bool dummy;
+ Maybe<nsCSSBorderRenderer> br =
+ static_cast<nsHTMLButtonControlFrame*>(mFrame)
+ ->CreateInnerFocusBorderRenderer(
+ aDisplayListBuilder, nullptr,
+ GetBounds(aDisplayListBuilder, &dummy),
+ nsRect(ToReferenceFrame(), mFrame->GetSize()), &borderIsEmpty);
+
+ if (!br) {
+ return borderIsEmpty;
+ }
+
+ aBuilder.StartGroup(this);
+ br->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
+ aBuilder.FinishGroup();
+
+ return true;
+}
+
+} // namespace mozilla
+
+static nsRect GetButtonInnerFocusRect(const nsIFrame* aFrame,
+ const ComputedStyle& aFocusStyle,
+ const nsRect& aRect) {
+ nsRect result = aRect;
+ result.Deflate(aFrame->GetUsedBorderAndPadding());
+
+ nsMargin innerFocusPadding;
+ aFocusStyle.StylePadding()->GetPadding(innerFocusPadding);
+
+ nsMargin framePadding = aFrame->GetUsedPadding();
+ innerFocusPadding.top = std::min(innerFocusPadding.top, framePadding.top);
+ innerFocusPadding.right =
+ std::min(innerFocusPadding.right, framePadding.right);
+ innerFocusPadding.bottom =
+ std::min(innerFocusPadding.bottom, framePadding.bottom);
+ innerFocusPadding.left = std::min(innerFocusPadding.left, framePadding.left);
+
+ result.Inflate(innerFocusPadding);
+ return result;
+}
+
+void nsHTMLButtonControlFrame::PaintInnerFocusBorder(
+ nsDisplayListBuilder* aBuilder, gfxContext& aRenderingContext,
+ const nsRect& aDirtyRect, const nsRect& aRect) {
+ if (!mInnerFocusStyle) {
+ return;
+ }
+
+ // we draw the -moz-focus-inner border just inside the button's
+ // normal border and padding, to match Windows themes.
+ PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
+ ? PaintBorderFlags::SyncDecodeImages
+ : PaintBorderFlags();
+
+ nsRect rect = GetButtonInnerFocusRect(this, *mInnerFocusStyle, aRect);
+ // We don't paint border images here, so the ImgDrawResult is useless.
+ Unused << nsCSSRendering::PaintBorder(PresContext(), aRenderingContext, this,
+ aDirtyRect, rect, mInnerFocusStyle,
+ flags);
+}
+
+Maybe<nsCSSBorderRenderer>
+nsHTMLButtonControlFrame::CreateInnerFocusBorderRenderer(
+ nsDisplayListBuilder* aBuilder, gfxContext* aRenderingContext,
+ const nsRect& aDirtyRect, const nsRect& aRect, bool* aBorderIsEmpty) {
+ if (!mInnerFocusStyle) {
+ return Nothing();
+ }
+
+ nsRect rect = GetButtonInnerFocusRect(this, *mInnerFocusStyle, aRect);
+ gfx::DrawTarget* dt =
+ aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
+ return nsCSSRendering::CreateBorderRenderer(PresContext(), dt, this,
+ aDirtyRect, rect,
+ mInnerFocusStyle, aBorderIsEmpty);
+}
+
void nsHTMLButtonControlFrame::BuildDisplayList(
nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) {
- nsDisplayList onTop(aBuilder);
if (IsVisibleForPainting()) {
// Clip the button itself to its border area for event hit testing.
Maybe<DisplayListClipState::AutoSaveRestore> eventClipState;
@@ -87,11 +206,9 @@ void nsHTMLButtonControlFrame::BuildDisplayList(
rect, hasRadii ? radii : nullptr);
}
- mRenderer.DisplayButton(aBuilder, aLists.BorderBackground(), &onTop);
+ DisplayBorderBackgroundOutline(aBuilder, aLists);
}
- nsDisplayListCollection set(aBuilder);
-
{
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
@@ -100,22 +217,23 @@ void nsHTMLButtonControlFrame::BuildDisplayList(
nsRect rect(aBuilder->ToReferenceFrame(this), GetSize());
rect.Deflate(border);
nscoord radii[8];
- bool hasRadii = GetPaddingBoxBorderRadii(radii);
+ const bool hasRadii = GetPaddingBoxBorderRadii(radii);
clipState.ClipContainingBlockDescendants(rect,
hasRadii ? radii : nullptr);
}
- BuildDisplayListForChild(aBuilder, mFrames.FirstChild(), set,
+ BuildDisplayListForChild(aBuilder, mFrames.FirstChild(), aLists,
DisplayChildFlag::ForcePseudoStackingContext);
}
- // Put the foreground outline and focus rects on top of the children
- set.Content()->AppendToTop(&onTop);
- set.MoveTo(aLists);
-
- DisplayOutline(aBuilder, aLists);
+ // Put the foreground outline on top of the children.
+ if (IsVisibleForPainting() && mInnerFocusStyle &&
+ mInnerFocusStyle->StyleBorder()->HasBorder() && IsThemed() &&
+ PresContext()->Theme()->ThemeWantsButtonInnerFocusRing()) {
+ aLists.Content()->AppendNewToTop<nsDisplayButtonForeground>(aBuilder, this);
+ }
- // to draw border when selected in editor
+ // To draw border when selected in editor
DisplaySelectionOverlay(aBuilder, aLists.Content());
}
@@ -237,12 +355,14 @@ void nsHTMLButtonControlFrame::ReflowButtonContents(
// Button has a fixed block-size -- that's its content-box bSize.
buttonContentBox.BSize(wm) = aButtonReflowInput.ComputedBSize();
} else {
- // Button is intrinsically sized -- it should shrinkwrap the
- // button-contents' bSize. But if it has size containment in block axis,
- // ignore the contents and use contain-intrinsic-block-size.
- nscoord bSize = aButtonReflowInput.mFrame->ContainIntrinsicBSize().valueOr(
- contentsDesiredSize.BSize(wm));
-
+ // Button is intrinsically sized -- it should shrinkwrap the contents'
+ // bSize.
+ // If we have size containment in block axis, ignore the contents and use
+ // contain-intrinsic-block-size. The combobox content size with no content
+ // is one line-height, not zero.
+ const Maybe<nscoord> containBSize = ContainIntrinsicBSize(
+ IsComboboxControlFrame() ? aButtonReflowInput.GetLineHeight() : 0);
+ const nscoord bSize = containBSize.valueOr(contentsDesiredSize.BSize(wm));
// Make sure we obey min/max-bSize in the case when we're doing intrinsic
// sizing (we get it for free when we have a non-intrinsic
// aButtonReflowInput.ComputedBSize()). Note that we do this before
@@ -359,12 +479,17 @@ nsresult nsHTMLButtonControlFrame::SetFormProperty(nsAtom* aName,
ComputedStyle* nsHTMLButtonControlFrame::GetAdditionalComputedStyle(
int32_t aIndex) const {
- return mRenderer.GetComputedStyle(aIndex);
+ if (aIndex == 0) {
+ return mInnerFocusStyle;
+ }
+ return nullptr;
}
void nsHTMLButtonControlFrame::SetAdditionalComputedStyle(
int32_t aIndex, ComputedStyle* aComputedStyle) {
- mRenderer.SetComputedStyle(aIndex, aComputedStyle);
+ if (aIndex == 0) {
+ mInnerFocusStyle = aComputedStyle;
+ }
}
void nsHTMLButtonControlFrame::AppendDirectlyOwnedAnonBoxes(
diff --git a/layout/forms/nsHTMLButtonControlFrame.h b/layout/forms/nsHTMLButtonControlFrame.h
index b4409d66a7..760418f954 100644
--- a/layout/forms/nsHTMLButtonControlFrame.h
+++ b/layout/forms/nsHTMLButtonControlFrame.h
@@ -7,10 +7,9 @@
#ifndef nsHTMLButtonControlFrame_h___
#define nsHTMLButtonControlFrame_h___
-#include "mozilla/Attributes.h"
#include "nsContainerFrame.h"
+#include "nsCSSRenderingBorders.h"
#include "nsIFormControlFrame.h"
-#include "nsButtonFrameRenderer.h"
class gfxContext;
class nsPresContext;
@@ -83,6 +82,14 @@ class nsHTMLButtonControlFrame : public nsContainerFrame,
// Return the ::-moz-button-content anonymous box.
void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
+ mozilla::Maybe<nsCSSBorderRenderer> CreateInnerFocusBorderRenderer(
+ nsDisplayListBuilder* aBuilder, gfxContext* aRenderingContext,
+ const nsRect& aDirtyRect, const nsRect& aRect, bool* aBorderIsEmpty);
+
+ void PaintInnerFocusBorder(nsDisplayListBuilder* aBuilder,
+ gfxContext& aRenderingContext,
+ const nsRect& aDirtyRect, const nsRect& aRect);
+
protected:
nsHTMLButtonControlFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
nsIFrame::ClassID aID);
@@ -90,7 +97,7 @@ class nsHTMLButtonControlFrame : public nsContainerFrame,
// Indicates whether we should clip our children's painting to our
// border-box (either because of "overflow" or because of legacy reasons
// about how <input>-flavored buttons work).
- bool ShouldClipPaintingToBorderBox();
+ bool ShouldClipPaintingToBorderBox() const;
// Reflows the button's sole child frame, and computes the desired size
// of the button itself from the results.
@@ -104,7 +111,7 @@ class nsHTMLButtonControlFrame : public nsContainerFrame,
mozilla::WritingMode aWM,
BaselineSharingGroup aBaselineGroup) const override;
- nsButtonFrameRenderer mRenderer;
+ RefPtr<mozilla::ComputedStyle> mInnerFocusStyle;
};
#endif
diff --git a/layout/forms/nsNumberControlFrame.cpp b/layout/forms/nsNumberControlFrame.cpp
index e8ed87c8f3..518ba91e24 100644
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -64,22 +64,29 @@ nsresult nsNumberControlFrame::CreateAnonymousContent(
nsTextControlFrame::CreateAnonymousContent(aElements);
+#if defined(MOZ_WIDGET_ANDROID)
+ // We don't want spin buttons on Android
+ return NS_OK;
+#else
// The author has elected to hide the spinner by setting this
// -moz-appearance. We will reframe if it changes.
- if (StyleDisplay()->EffectiveAppearance() != StyleAppearance::Textfield) {
- // Create the ::-moz-number-spin-box pseudo-element:
- mSpinBox = MakeAnonElement(PseudoStyleType::mozNumberSpinBox);
+ if (StyleDisplay()->EffectiveAppearance() == StyleAppearance::Textfield) {
+ return NS_OK;
+ }
- // Create the ::-moz-number-spin-up pseudo-element:
- mSpinUp = MakeAnonElement(PseudoStyleType::mozNumberSpinUp, mSpinBox);
+ // Create the ::-moz-number-spin-box pseudo-element:
+ mSpinBox = MakeAnonElement(PseudoStyleType::mozNumberSpinBox);
- // Create the ::-moz-number-spin-down pseudo-element:
- mSpinDown = MakeAnonElement(PseudoStyleType::mozNumberSpinDown, mSpinBox);
+ // Create the ::-moz-number-spin-up pseudo-element:
+ mSpinUp = MakeAnonElement(PseudoStyleType::mozNumberSpinUp, mSpinBox);
- aElements.AppendElement(mSpinBox);
- }
+ // Create the ::-moz-number-spin-down pseudo-element:
+ mSpinDown = MakeAnonElement(PseudoStyleType::mozNumberSpinDown, mSpinBox);
+
+ aElements.AppendElement(mSpinBox);
return NS_OK;
+#endif
}
/* static */
diff --git a/layout/forms/test/test_bug536567_perwindowpb.html b/layout/forms/test/test_bug536567_perwindowpb.html
index 224b2c74a4..e27803157e 100644
--- a/layout/forms/test/test_bug536567_perwindowpb.html
+++ b/layout/forms/test/test_bug536567_perwindowpb.html
@@ -19,7 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=536567
const Cm = Components.manager;
var MockFilePicker = SpecialPowers.MockFilePicker;
-MockFilePicker.init(window);
+MockFilePicker.init(SpecialPowers.wrap(window).browsingContext);
var tmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
var homeDir = Services.dirsvc.get("Desk", Ci.nsIFile);
diff --git a/layout/forms/test/test_bug935876.html b/layout/forms/test/test_bug935876.html
index 4488fdf962..465fcac732 100644
--- a/layout/forms/test/test_bug935876.html
+++ b/layout/forms/test/test_bug935876.html
@@ -112,7 +112,7 @@ function runTests()
var listbox = document.getElementById("listbox");
listbox.addEventListener("keydown", onKeydown);
listbox.addEventListener("keypress", onKeypress);
- SpecialPowers.addSystemEventListener(listbox, "keydown", onkeydownInSystemEventGroup, false);
+ SpecialPowers.wrap(listbox).addEventListener("keydown", onkeydownInSystemEventGroup, { mozSystemGroup: true });
listbox.focus();
@@ -185,14 +185,13 @@ function runTests()
listbox.removeEventListener("keydown", onKeydown);
listbox.removeEventListener("keypress", onKeypress);
- SpecialPowers.removeSystemEventListener(listbox, "keydown", onkeydownInSystemEventGroup, false);
-
+ SpecialPowers.wrap(listbox).removeEventListener("keydown", onkeydownInSystemEventGroup, { mozSystemGroup: true });
var multipleListbox = document.getElementById("multipleListbox");
multipleListbox.addEventListener("keydown", onKeydown);
multipleListbox.addEventListener("keypress", onKeypress);
- SpecialPowers.addSystemEventListener(multipleListbox, "keydown", onkeydownInSystemEventGroup, false);
+ SpecialPowers.wrap(multipleListbox).addEventListener("keydown", onkeydownInSystemEventGroup, { mozSystemGroup: true });
multipleListbox.focus();
@@ -265,14 +264,13 @@ function runTests()
multipleListbox.removeEventListener("keydown", onKeydown);
multipleListbox.removeEventListener("keypress", onKeypress);
- SpecialPowers.removeSystemEventListener(multipleListbox, "keydown", onkeydownInSystemEventGroup, false);
-
+ SpecialPowers.wrap(multipleListbox).removeEventListener("keydown", onkeydownInSystemEventGroup, { mozSystemGroup: true });
var combobox = document.getElementById("combobox");
combobox.addEventListener("keydown", onKeydown);
combobox.addEventListener("keypress", onKeypress);
- SpecialPowers.addSystemEventListener(combobox, "keydown", onkeydownInSystemEventGroup, false);
+ SpecialPowers.wrap(combobox).addEventListener("keydown", onkeydownInSystemEventGroup, { mozSystemGroup: true });
combobox.focus();
@@ -353,7 +351,7 @@ function runTests()
{
combobox.removeEventListener("keydown", onKeydown);
combobox.removeEventListener("keypress", onKeypress);
- SpecialPowers.removeSystemEventListener(combobox, "keydown", onkeydownInSystemEventGroup, false);
+ SpecialPowers.wrap(combobox).removeEventListener("keydown", onkeydownInSystemEventGroup, { mozSystemGroup: true });
SimpleTest.finish();
}