forked from mirrors/gecko-dev
This makes it easier to get parity between legacy and regular flex without having to either have tons of arbitrary attribute selectors in the xul sheet, nor adding attribute lookup hacks to the html flexbox layout. Also, reimplement the remaining supported flex attribute-values (0 and 1) purely in terms of CSS rules in xul.css (regardless of whether emulate-moz-box-with-flex is enabled). In practice these are pretty uncommon and the style attribute does the trick in every case I've tried. Add a debug-only assertion to ensure we preserve behavior for now. Add a new test with another behavior difference between flexbox emulation and old xul layout because the old reftest now passes. Use replaced elements, which in modern flex are treated differently. Differential Revision: https://phabricator.services.mozilla.com/D154394
546 lines
17 KiB
C++
546 lines
17 KiB
C++
/* -*- 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 "nsScrollbarFrame.h"
|
|
#include "nsSliderFrame.h"
|
|
#include "nsScrollbarButtonFrame.h"
|
|
#include "nsContentCreatorFunctions.h"
|
|
#include "nsGkAtoms.h"
|
|
#include "nsIScrollableFrame.h"
|
|
#include "nsIScrollbarMediator.h"
|
|
#include "nsStyleConsts.h"
|
|
#include "nsIContent.h"
|
|
#include "mozilla/LookAndFeel.h"
|
|
#include "mozilla/PresShell.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include "mozilla/dom/MutationEventBinding.h"
|
|
#include "mozilla/StaticPrefs_apz.h"
|
|
|
|
using namespace mozilla;
|
|
using mozilla::dom::Element;
|
|
|
|
//
|
|
// NS_NewScrollbarFrame
|
|
//
|
|
// Creates a new scrollbar frame and returns it
|
|
//
|
|
nsIFrame* NS_NewScrollbarFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
|
|
return new (aPresShell)
|
|
nsScrollbarFrame(aStyle, aPresShell->GetPresContext());
|
|
}
|
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarFrame)
|
|
|
|
NS_QUERYFRAME_HEAD(nsScrollbarFrame)
|
|
NS_QUERYFRAME_ENTRY(nsScrollbarFrame)
|
|
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
|
|
|
|
void nsScrollbarFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|
nsIFrame* aPrevInFlow) {
|
|
nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
|
|
|
|
// We want to be a reflow root since we use reflows to move the
|
|
// slider. Any reflow inside the scrollbar frame will be a reflow to
|
|
// move the slider and will thus not change anything outside of the
|
|
// scrollbar or change the size of the scrollbar frame.
|
|
AddStateBits(NS_FRAME_REFLOW_ROOT);
|
|
}
|
|
|
|
void nsScrollbarFrame::DestroyFrom(nsIFrame* aDestructRoot,
|
|
PostDestroyData& aPostDestroyData) {
|
|
aPostDestroyData.AddAnonymousContent(mUpTopButton.forget());
|
|
aPostDestroyData.AddAnonymousContent(mDownTopButton.forget());
|
|
aPostDestroyData.AddAnonymousContent(mSlider.forget());
|
|
aPostDestroyData.AddAnonymousContent(mUpBottomButton.forget());
|
|
aPostDestroyData.AddAnonymousContent(mDownBottomButton.forget());
|
|
nsBoxFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
|
|
}
|
|
|
|
void nsScrollbarFrame::Reflow(nsPresContext* aPresContext,
|
|
ReflowOutput& aDesiredSize,
|
|
const ReflowInput& aReflowInput,
|
|
nsReflowStatus& aStatus) {
|
|
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
|
|
|
|
nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
|
|
|
|
// nsGfxScrollFrame may have told us to shrink to nothing. If so, make sure
|
|
// our desired size agrees.
|
|
if (aReflowInput.AvailableWidth() == 0) {
|
|
aDesiredSize.Width() = 0;
|
|
}
|
|
if (aReflowInput.AvailableHeight() == 0) {
|
|
aDesiredSize.Height() = 0;
|
|
}
|
|
}
|
|
|
|
nsresult nsScrollbarFrame::AttributeChanged(int32_t aNameSpaceID,
|
|
nsAtom* aAttribute,
|
|
int32_t aModType) {
|
|
nsresult rv =
|
|
nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
|
|
|
|
// Update value in our children
|
|
UpdateChildrenAttributeValue(aAttribute, true);
|
|
|
|
// if the current position changes, notify any nsGfxScrollFrame
|
|
// parent we may have
|
|
if (aAttribute != nsGkAtoms::curpos) return rv;
|
|
|
|
nsIScrollableFrame* scrollable = do_QueryFrame(GetParent());
|
|
if (!scrollable) return rv;
|
|
|
|
nsCOMPtr<nsIContent> content(mContent);
|
|
scrollable->CurPosAttributeChanged(content);
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsScrollbarFrame::HandlePress(nsPresContext* aPresContext,
|
|
WidgetGUIEvent* aEvent,
|
|
nsEventStatus* aEventStatus) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsScrollbarFrame::HandleMultiplePress(nsPresContext* aPresContext,
|
|
WidgetGUIEvent* aEvent,
|
|
nsEventStatus* aEventStatus,
|
|
bool aControlHeld) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsScrollbarFrame::HandleDrag(nsPresContext* aPresContext,
|
|
WidgetGUIEvent* aEvent,
|
|
nsEventStatus* aEventStatus) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsScrollbarFrame::HandleRelease(nsPresContext* aPresContext,
|
|
WidgetGUIEvent* aEvent,
|
|
nsEventStatus* aEventStatus) {
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsScrollbarFrame::SetScrollbarMediatorContent(nsIContent* aMediator) {
|
|
mScrollbarMediator = aMediator;
|
|
}
|
|
|
|
nsIScrollbarMediator* nsScrollbarFrame::GetScrollbarMediator() {
|
|
if (!mScrollbarMediator) {
|
|
return nullptr;
|
|
}
|
|
nsIFrame* f = mScrollbarMediator->GetPrimaryFrame();
|
|
nsIScrollableFrame* scrollFrame = do_QueryFrame(f);
|
|
nsIScrollbarMediator* sbm;
|
|
|
|
if (scrollFrame) {
|
|
nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
|
|
sbm = do_QueryFrame(scrolledFrame);
|
|
if (sbm) {
|
|
return sbm;
|
|
}
|
|
}
|
|
sbm = do_QueryFrame(f);
|
|
if (f && !sbm) {
|
|
f = f->PresShell()->GetRootScrollFrame();
|
|
if (f && f->GetContent() == mScrollbarMediator) {
|
|
return do_QueryFrame(f);
|
|
}
|
|
}
|
|
return sbm;
|
|
}
|
|
|
|
nsresult nsScrollbarFrame::GetXULMargin(nsMargin& aMargin) {
|
|
aMargin.SizeTo(0, 0, 0, 0);
|
|
|
|
const bool overlayScrollbars = PresContext()->UseOverlayScrollbars();
|
|
|
|
const bool horizontal = IsXULHorizontal();
|
|
bool didSetMargin = false;
|
|
|
|
if (overlayScrollbars) {
|
|
nsSize minSize;
|
|
bool widthSet = false;
|
|
bool heightSet = false;
|
|
AddXULMinSize(this, minSize, widthSet, heightSet);
|
|
if (horizontal) {
|
|
if (heightSet) {
|
|
aMargin.top = -minSize.height;
|
|
didSetMargin = true;
|
|
}
|
|
} else {
|
|
if (widthSet) {
|
|
aMargin.left = -minSize.width;
|
|
didSetMargin = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!didSetMargin) {
|
|
DebugOnly<nsresult> rv = nsIFrame::GetXULMargin(aMargin);
|
|
// TODO(emilio): Should probably not be fallible, it's not like anybody
|
|
// cares about the return value anyway.
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "nsIFrame::GetXULMargin can't really fail");
|
|
}
|
|
|
|
if (!horizontal) {
|
|
nsIScrollbarMediator* scrollFrame = GetScrollbarMediator();
|
|
if (scrollFrame && !scrollFrame->IsScrollbarOnRight()) {
|
|
std::swap(aMargin.left, aMargin.right);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsScrollbarFrame::SetIncrementToLine(int32_t aDirection) {
|
|
mSmoothScroll = true;
|
|
mDirection = aDirection;
|
|
mScrollUnit = ScrollUnit::LINES;
|
|
|
|
// get the scrollbar's content node
|
|
nsIContent* content = GetContent();
|
|
mIncrement = aDirection * nsSliderFrame::GetIncrement(content);
|
|
}
|
|
|
|
void nsScrollbarFrame::SetIncrementToPage(int32_t aDirection) {
|
|
mSmoothScroll = true;
|
|
mDirection = aDirection;
|
|
mScrollUnit = ScrollUnit::PAGES;
|
|
|
|
// get the scrollbar's content node
|
|
nsIContent* content = GetContent();
|
|
mIncrement = aDirection * nsSliderFrame::GetPageIncrement(content);
|
|
}
|
|
|
|
void nsScrollbarFrame::SetIncrementToWhole(int32_t aDirection) {
|
|
// Don't repeat or use smooth scrolling if scrolling to beginning or end
|
|
// of a page.
|
|
mSmoothScroll = false;
|
|
mDirection = aDirection;
|
|
mScrollUnit = ScrollUnit::WHOLE;
|
|
|
|
// get the scrollbar's content node
|
|
nsIContent* content = GetContent();
|
|
if (aDirection == -1)
|
|
mIncrement = -nsSliderFrame::GetCurrentPosition(content);
|
|
else
|
|
mIncrement = nsSliderFrame::GetMaxPosition(content) -
|
|
nsSliderFrame::GetCurrentPosition(content);
|
|
}
|
|
|
|
int32_t nsScrollbarFrame::MoveToNewPosition(
|
|
ImplementsScrollByUnit aImplementsScrollByUnit) {
|
|
if (aImplementsScrollByUnit == ImplementsScrollByUnit::Yes &&
|
|
StaticPrefs::apz_scrollbarbuttonrepeat_enabled()) {
|
|
nsIScrollbarMediator* m = GetScrollbarMediator();
|
|
MOZ_ASSERT(m);
|
|
// aImplementsScrollByUnit being Yes indicates the caller doesn't care
|
|
// about the return value.
|
|
// Note that this `MoveToNewPosition` is used for scrolling triggered by
|
|
// repeating scrollbar button press, so we'd use an intended-direction
|
|
// scroll snap flag.
|
|
m->ScrollByUnit(
|
|
this, mSmoothScroll ? ScrollMode::Smooth : ScrollMode::Instant,
|
|
mDirection, mScrollUnit, ScrollSnapFlags::IntendedDirection);
|
|
return 0;
|
|
}
|
|
|
|
// get the scrollbar's content node
|
|
RefPtr<Element> content = GetContent()->AsElement();
|
|
|
|
// get the current pos
|
|
int32_t curpos = nsSliderFrame::GetCurrentPosition(content);
|
|
|
|
// get the max pos
|
|
int32_t maxpos = nsSliderFrame::GetMaxPosition(content);
|
|
|
|
// increment the given amount
|
|
if (mIncrement) {
|
|
curpos += mIncrement;
|
|
}
|
|
|
|
// make sure the current position is between the current and max positions
|
|
if (curpos < 0) {
|
|
curpos = 0;
|
|
} else if (curpos > maxpos) {
|
|
curpos = maxpos;
|
|
}
|
|
|
|
// set the current position of the slider.
|
|
nsAutoString curposStr;
|
|
curposStr.AppendInt(curpos);
|
|
|
|
AutoWeakFrame weakFrame(this);
|
|
if (mSmoothScroll) {
|
|
content->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, u"true"_ns, false);
|
|
}
|
|
content->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curposStr, false);
|
|
// notify the nsScrollbarFrame of the change
|
|
AttributeChanged(kNameSpaceID_None, nsGkAtoms::curpos,
|
|
dom::MutationEvent_Binding::MODIFICATION);
|
|
if (!weakFrame.IsAlive()) {
|
|
return curpos;
|
|
}
|
|
// notify all nsSliderFrames of the change
|
|
for (const auto& childList : ChildLists()) {
|
|
for (nsIFrame* f : childList.mList) {
|
|
nsSliderFrame* sliderFrame = do_QueryFrame(f);
|
|
if (sliderFrame) {
|
|
sliderFrame->AttributeChanged(kNameSpaceID_None, nsGkAtoms::curpos,
|
|
dom::MutationEvent_Binding::MODIFICATION);
|
|
if (!weakFrame.IsAlive()) {
|
|
return curpos;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false);
|
|
return curpos;
|
|
}
|
|
|
|
static already_AddRefed<Element> MakeScrollbarButton(
|
|
dom::NodeInfo* aNodeInfo, bool aVertical, bool aBottom, bool aDown,
|
|
AnonymousContentKey& aKey) {
|
|
MOZ_ASSERT(aNodeInfo);
|
|
MOZ_ASSERT(
|
|
aNodeInfo->Equals(nsGkAtoms::scrollbarbutton, nullptr, kNameSpaceID_XUL));
|
|
|
|
static constexpr nsLiteralString kSbattrValues[2][2] = {
|
|
{
|
|
u"scrollbar-up-top"_ns,
|
|
u"scrollbar-up-bottom"_ns,
|
|
},
|
|
{
|
|
u"scrollbar-down-top"_ns,
|
|
u"scrollbar-down-bottom"_ns,
|
|
},
|
|
};
|
|
|
|
static constexpr nsLiteralString kTypeValues[2] = {
|
|
u"decrement"_ns,
|
|
u"increment"_ns,
|
|
};
|
|
|
|
aKey = AnonymousContentKey::Type_ScrollbarButton;
|
|
if (aVertical) {
|
|
aKey |= AnonymousContentKey::Flag_Vertical;
|
|
}
|
|
if (aBottom) {
|
|
aKey |= AnonymousContentKey::Flag_ScrollbarButton_Bottom;
|
|
}
|
|
if (aDown) {
|
|
aKey |= AnonymousContentKey::Flag_ScrollbarButton_Down;
|
|
}
|
|
|
|
RefPtr<Element> e;
|
|
NS_TrustedNewXULElement(getter_AddRefs(e), do_AddRef(aNodeInfo));
|
|
e->SetAttr(kNameSpaceID_None, nsGkAtoms::sbattr,
|
|
kSbattrValues[aDown][aBottom], false);
|
|
e->SetAttr(kNameSpaceID_None, nsGkAtoms::type, kTypeValues[aDown], false);
|
|
return e.forget();
|
|
}
|
|
|
|
nsresult nsScrollbarFrame::CreateAnonymousContent(
|
|
nsTArray<ContentInfo>& aElements) {
|
|
nsNodeInfoManager* nodeInfoManager = mContent->NodeInfo()->NodeInfoManager();
|
|
|
|
Element* el(GetContent()->AsElement());
|
|
|
|
// If there are children already in the node, don't create any anonymous
|
|
// content (this only apply to crashtests/369038-1.xhtml)
|
|
if (el->HasChildren()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsAutoString orient;
|
|
el->GetAttr(kNameSpaceID_None, nsGkAtoms::orient, orient);
|
|
bool vertical = orient.EqualsLiteral("vertical");
|
|
|
|
RefPtr<dom::NodeInfo> sbbNodeInfo =
|
|
nodeInfoManager->GetNodeInfo(nsGkAtoms::scrollbarbutton, nullptr,
|
|
kNameSpaceID_XUL, nsINode::ELEMENT_NODE);
|
|
|
|
bool createButtons = PresContext()->Theme()->ThemeSupportsScrollbarButtons();
|
|
|
|
if (createButtons) {
|
|
AnonymousContentKey key;
|
|
mUpTopButton =
|
|
MakeScrollbarButton(sbbNodeInfo, vertical, /* aBottom */ false,
|
|
/* aDown */ false, key);
|
|
aElements.AppendElement(ContentInfo(mUpTopButton, key));
|
|
}
|
|
|
|
if (createButtons) {
|
|
AnonymousContentKey key;
|
|
mDownTopButton =
|
|
MakeScrollbarButton(sbbNodeInfo, vertical, /* aBottom */ false,
|
|
/* aDown */ true, key);
|
|
aElements.AppendElement(ContentInfo(mDownTopButton, key));
|
|
}
|
|
|
|
{
|
|
AnonymousContentKey key = AnonymousContentKey::Type_Slider;
|
|
if (vertical) {
|
|
key |= AnonymousContentKey::Flag_Vertical;
|
|
}
|
|
|
|
NS_TrustedNewXULElement(
|
|
getter_AddRefs(mSlider),
|
|
nodeInfoManager->GetNodeInfo(nsGkAtoms::slider, nullptr,
|
|
kNameSpaceID_XUL, nsINode::ELEMENT_NODE));
|
|
mSlider->SetAttr(kNameSpaceID_None, nsGkAtoms::orient, orient, false);
|
|
|
|
aElements.AppendElement(ContentInfo(mSlider, key));
|
|
|
|
NS_TrustedNewXULElement(
|
|
getter_AddRefs(mThumb),
|
|
nodeInfoManager->GetNodeInfo(nsGkAtoms::thumb, nullptr,
|
|
kNameSpaceID_XUL, nsINode::ELEMENT_NODE));
|
|
mThumb->SetAttr(kNameSpaceID_None, nsGkAtoms::orient, orient, false);
|
|
mSlider->AppendChildTo(mThumb, false, IgnoreErrors());
|
|
}
|
|
|
|
if (createButtons) {
|
|
AnonymousContentKey key;
|
|
mUpBottomButton =
|
|
MakeScrollbarButton(sbbNodeInfo, vertical, /* aBottom */ true,
|
|
/* aDown */ false, key);
|
|
aElements.AppendElement(ContentInfo(mUpBottomButton, key));
|
|
}
|
|
|
|
if (createButtons) {
|
|
AnonymousContentKey key;
|
|
mDownBottomButton =
|
|
MakeScrollbarButton(sbbNodeInfo, vertical, /* aBottom */ true,
|
|
/* aDown */ true, key);
|
|
aElements.AppendElement(ContentInfo(mDownBottomButton, key));
|
|
}
|
|
|
|
// Don't cache styles if we are inside a <select> element, since we have
|
|
// some UA style sheet rules that depend on the <select>'s attributes.
|
|
if (GetContent()->GetParent() &&
|
|
GetContent()->GetParent()->IsHTMLElement(nsGkAtoms::select)) {
|
|
for (auto& info : aElements) {
|
|
info.mKey = AnonymousContentKey::None;
|
|
}
|
|
}
|
|
|
|
UpdateChildrenAttributeValue(nsGkAtoms::curpos, false);
|
|
UpdateChildrenAttributeValue(nsGkAtoms::maxpos, false);
|
|
UpdateChildrenAttributeValue(nsGkAtoms::disabled, false);
|
|
UpdateChildrenAttributeValue(nsGkAtoms::pageincrement, false);
|
|
UpdateChildrenAttributeValue(nsGkAtoms::increment, false);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsScrollbarFrame::UpdateChildrenAttributeValue(nsAtom* aAttribute,
|
|
bool aNotify) {
|
|
Element* el(GetContent()->AsElement());
|
|
|
|
nsAutoString value;
|
|
el->GetAttr(kNameSpaceID_None, aAttribute, value);
|
|
|
|
if (!el->HasAttr(kNameSpaceID_None, aAttribute)) {
|
|
if (mUpTopButton) {
|
|
mUpTopButton->UnsetAttr(kNameSpaceID_None, aAttribute, aNotify);
|
|
}
|
|
if (mDownTopButton) {
|
|
mDownTopButton->UnsetAttr(kNameSpaceID_None, aAttribute, aNotify);
|
|
}
|
|
if (mSlider) {
|
|
mSlider->UnsetAttr(kNameSpaceID_None, aAttribute, aNotify);
|
|
}
|
|
if (mThumb && aAttribute == nsGkAtoms::disabled) {
|
|
mThumb->UnsetAttr(kNameSpaceID_None, nsGkAtoms::collapsed, aNotify);
|
|
}
|
|
if (mUpBottomButton) {
|
|
mUpBottomButton->UnsetAttr(kNameSpaceID_None, aAttribute, aNotify);
|
|
}
|
|
if (mDownBottomButton) {
|
|
mDownBottomButton->UnsetAttr(kNameSpaceID_None, aAttribute, aNotify);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (aAttribute == nsGkAtoms::curpos || aAttribute == nsGkAtoms::maxpos) {
|
|
if (mUpTopButton) {
|
|
mUpTopButton->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
if (mDownTopButton) {
|
|
mDownTopButton->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
if (mSlider) {
|
|
mSlider->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
if (mUpBottomButton) {
|
|
mUpBottomButton->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
if (mDownBottomButton) {
|
|
mDownBottomButton->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
} else if (aAttribute == nsGkAtoms::disabled) {
|
|
if (mUpTopButton) {
|
|
mUpTopButton->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
if (mDownTopButton) {
|
|
mDownTopButton->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
if (mSlider) {
|
|
mSlider->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
// Set the value on "collapsed" attribute.
|
|
if (mThumb) {
|
|
mThumb->SetAttr(kNameSpaceID_None, nsGkAtoms::collapsed, value, aNotify);
|
|
}
|
|
if (mUpBottomButton) {
|
|
mUpBottomButton->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
if (mDownBottomButton) {
|
|
mDownBottomButton->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
} else if (aAttribute == nsGkAtoms::pageincrement ||
|
|
aAttribute == nsGkAtoms::increment) {
|
|
if (mSlider) {
|
|
mSlider->SetAttr(kNameSpaceID_None, aAttribute, value, aNotify);
|
|
}
|
|
}
|
|
}
|
|
|
|
void nsScrollbarFrame::AppendAnonymousContentTo(
|
|
nsTArray<nsIContent*>& aElements, uint32_t aFilter) {
|
|
if (mUpTopButton) {
|
|
aElements.AppendElement(mUpTopButton);
|
|
}
|
|
|
|
if (mDownTopButton) {
|
|
aElements.AppendElement(mDownTopButton);
|
|
}
|
|
|
|
if (mSlider) {
|
|
aElements.AppendElement(mSlider);
|
|
}
|
|
|
|
if (mUpBottomButton) {
|
|
aElements.AppendElement(mUpBottomButton);
|
|
}
|
|
|
|
if (mDownBottomButton) {
|
|
aElements.AppendElement(mDownBottomButton);
|
|
}
|
|
}
|