diff options
Diffstat (limited to 'layout/xul/tree/nsTreeColFrame.cpp')
-rw-r--r-- | layout/xul/tree/nsTreeColFrame.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/layout/xul/tree/nsTreeColFrame.cpp b/layout/xul/tree/nsTreeColFrame.cpp new file mode 100644 index 0000000000..d075da8a72 --- /dev/null +++ b/layout/xul/tree/nsTreeColFrame.cpp @@ -0,0 +1,169 @@ +/* -*- 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 "nsTreeColFrame.h" + +#include "mozilla/ComputedStyle.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/PresShell.h" +#include "mozilla/dom/XULTreeElement.h" +#include "mozilla/CSSOrderAwareFrameIterator.h" +#include "nsCOMPtr.h" +#include "nsGkAtoms.h" +#include "nsIContent.h" +#include "nsNameSpaceManager.h" +#include "nsTreeColumns.h" +#include "nsDisplayList.h" +#include "nsTreeBodyFrame.h" +#include "nsXULElement.h" + +using namespace mozilla; +using namespace mozilla::dom; + +// +// NS_NewTreeColFrame +// +// Creates a new col frame +// +nsIFrame* NS_NewTreeColFrame(PresShell* aPresShell, ComputedStyle* aStyle) { + return new (aPresShell) nsTreeColFrame(aStyle, aPresShell->GetPresContext()); +} + +NS_IMPL_FRAMEARENA_HELPERS(nsTreeColFrame) + +// Destructor +nsTreeColFrame::~nsTreeColFrame() = default; + +void nsTreeColFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, + nsIFrame* aPrevInFlow) { + nsBoxFrame::Init(aContent, aParent, aPrevInFlow); + InvalidateColumns(); +} + +void nsTreeColFrame::DestroyFrom(nsIFrame* aDestructRoot, + PostDestroyData& aPostDestroyData) { + InvalidateColumns(false); + nsBoxFrame::DestroyFrom(aDestructRoot, aPostDestroyData); +} + +nsresult nsTreeColFrame::AttributeChanged(int32_t aNameSpaceID, + nsAtom* aAttribute, + int32_t aModType) { + nsresult rv = + nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); + + if (aAttribute == nsGkAtoms::primary) { + InvalidateColumns(); + } + + return rv; +} + +void nsTreeColFrame::SetXULBounds(nsBoxLayoutState& aBoxLayoutState, + const nsRect& aRect, + bool aRemoveOverflowArea) { + nscoord oldWidth = mRect.width; + + nsBoxFrame::SetXULBounds(aBoxLayoutState, aRect, aRemoveOverflowArea); + if (mRect.width != oldWidth) { + RefPtr<XULTreeElement> tree = GetTree(); + if (tree) { + tree->Invalidate(); + } + } +} + +XULTreeElement* nsTreeColFrame::GetTree() { + nsIContent* parent = mContent->GetParent(); + return parent ? XULTreeElement::FromNodeOrNull(parent->GetParent()) : nullptr; +} + +void nsTreeColFrame::InvalidateColumns(bool aCanWalkFrameTree) { + RefPtr<XULTreeElement> tree = GetTree(); + if (!tree) { + return; + } + + nsTreeBodyFrame* body = aCanWalkFrameTree + ? tree->GetTreeBodyFrame(FlushType::None) + : tree->GetCachedTreeBodyFrame(); + + if (!body) { + return; + } + + RefPtr<nsTreeColumns> columns = body->Columns(); + if (!columns) { + return; + } + + columns->InvalidateColumns(); +} + +namespace mozilla { + +class nsDisplayXULTreeColSplitterTarget final : public nsDisplayItem { + public: + nsDisplayXULTreeColSplitterTarget(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame) { + MOZ_COUNT_CTOR(nsDisplayXULTreeColSplitterTarget); + } + MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayXULTreeColSplitterTarget) + + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, + nsTArray<nsIFrame*>* aOutFrames) override; + NS_DISPLAY_DECL_NAME("XULTreeColSplitterTarget", + TYPE_XUL_TREE_COL_SPLITTER_TARGET) +}; + +void nsDisplayXULTreeColSplitterTarget::HitTest( + nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, + nsTArray<nsIFrame*>* aOutFrames) { + nsRect rect = aRect - ToReferenceFrame(); + // If we are in either in the first 4 pixels or the last 4 pixels, we're going + // to do something really strange. Check for an adjacent splitter. + bool left = false; + bool right = false; + if (mFrame->GetSize().width - nsPresContext::CSSPixelsToAppUnits(4) <= + rect.XMost()) { + right = true; + } else if (nsPresContext::CSSPixelsToAppUnits(4) > rect.x) { + left = true; + } + + // Swap left and right for RTL trees in order to find the correct splitter + if (mFrame->StyleVisibility()->mDirection == StyleDirection::Rtl) { + std::swap(left, right); + } + + if (left || right) { + nsIFrame* child = nsBoxFrame::SlowOrdinalGroupAwareSibling(mFrame, right); + // We are a header. Look for the correct splitter. + if (child && child->GetContent()->IsXULElement(nsGkAtoms::splitter)) { + aOutFrames->AppendElement(child); + } + } +} + +} // namespace mozilla + +void nsTreeColFrame::BuildDisplayListForChildren( + nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { + if (!aBuilder->IsForEventDelivery()) { + nsBoxFrame::BuildDisplayListForChildren(aBuilder, aLists); + return; + } + + nsDisplayListCollection set(aBuilder); + nsBoxFrame::BuildDisplayListForChildren(aBuilder, set); + + WrapListsInRedirector(aBuilder, set, aLists); + + aLists.Content()->AppendNewToTop<nsDisplayXULTreeColSplitterTarget>(aBuilder, + this); +} |