Quellcode-Bibliothek nsScrollbarFrame.cpp
Sprache: 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 //
// 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::InvalidateForHoverChange(bool aIsNowHovered) { // Hover state on the scrollbar changes both the scrollbar and potentially // descendants too, so invalidate when it changes.
InvalidateFrameSubtree(); if (!aIsNowHovered) { return;
}
mHasBeenHovered = true; // When hovering over one scrollbar, remove the sticky hover effect from the // opposite scrollbar, if needed. if (auto* opposite = GetOppositeScrollbar();
opposite && opposite->mHasBeenHovered) {
opposite->mHasBeenHovered = false;
opposite->InvalidateFrameSubtree();
}
}
void nsScrollbarFrame::Reflow(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
MarkInReflow();
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// We always take all the space we're given, and our track size in the other // axis. constbool horizontal = IsHorizontal(); constauto wm = GetWritingMode(); constauto minSize = aReflowInput.ComputedMinSize();
aDesiredSize.ISize(wm) = aReflowInput.ComputedISize();
aDesiredSize.BSize(wm) = [&] { if (aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE) { return aReflowInput.ComputedBSize();
} // We don't want to change our size during incremental reflow, see the // reflow root comment in init. if (!aReflowInput.mParentReflowInput) { return GetLogicalSize(wm).BSize(wm);
} return minSize.BSize(wm);
}();
// Layout our kids left to right / top to bottom. for (nsIFrame* kid : mFrames) {
MOZ_ASSERT(!kid->GetWritingMode().IsOrthogonalTo(wm), "We don't expect orthogonal scrollbar parts"); constbool isSlider = kid->GetContent() == mSlider;
LogicalSize availSize = totalAvailSize;
{ // Assume we'll consume the same size before and after the slider. This is // not a technically correct assumption if we have weird scrollbar button // setups, but those will be going away, see bug 1824254. const int32_t factor = isSlider ? 2 : 1; if (movesInInlineDirection) {
availSize.ISize(wm) =
std::max(0, totalAvailSize.ISize(wm) - nextKidPos.I(wm) * factor);
} else {
availSize.BSize(wm) =
std::max(0, totalAvailSize.BSize(wm) - nextKidPos.B(wm) * factor);
}
}
ReflowInput kidRI(aPresContext, aReflowInput, kid, availSize); if (isSlider) { // We want for the slider to take all the remaining available space.
kidRI.SetComputedISize(availSize.ISize(wm));
kidRI.SetComputedBSize(availSize.BSize(wm));
} elseif (movesInInlineDirection) { // Otherwise we want all the space in the axis we're not advancing in, and // the default / minimum size on the other axis.
kidRI.SetComputedBSize(availSize.BSize(wm));
} else {
kidRI.SetComputedISize(availSize.ISize(wm));
}
ReflowOutput kidDesiredSize(wm);
nsReflowStatus status; constauto flags = ReflowChildFlags::Default;
ReflowChild(kid, aPresContext, kidDesiredSize, kidRI, wm, nextKidPos,
containerSize, flags, status); // We haven't seen the slider yet, we can advance
FinishReflowChild(kid, aPresContext, kidDesiredSize, &kidRI, wm, nextKidPos,
containerSize, flags); if (movesInInlineDirection) {
nextKidPos.I(wm) += kidDesiredSize.ISize(wm);
} else {
nextKidPos.B(wm) += kidDesiredSize.BSize(wm);
}
}
// 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;
} elseif (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 (constauto& 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;
}
// 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;
}
// 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;
}
}
if (mDownTopButton) {
aElements.AppendElement(mDownTopButton);
}
if (mSlider) {
aElements.AppendElement(mSlider);
}
if (mUpBottomButton) {
aElements.AppendElement(mUpBottomButton);
}
if (mDownBottomButton) {
aElements.AppendElement(mDownBottomButton);
}
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.37Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.