tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XULTreeElement.cpp (11325B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/XULTreeElement.h"
      8 
      9 #include "ChildIterator.h"
     10 #include "mozilla/dom/BindingUtils.h"
     11 #include "mozilla/dom/DOMRect.h"
     12 #include "mozilla/dom/Element.h"
     13 #include "mozilla/dom/ToJSValue.h"
     14 #include "mozilla/dom/XULTreeElementBinding.h"
     15 #include "nsCOMPtr.h"
     16 #include "nsError.h"
     17 #include "nsITreeSelection.h"
     18 #include "nsScrollbarFrame.h"
     19 #include "nsTreeBodyFrame.h"
     20 #include "nsTreeContentView.h"
     21 
     22 namespace mozilla::dom {
     23 
     24 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULTreeElement, nsXULElement)
     25 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeElement, nsXULElement, mView)
     26 
     27 JSObject* XULTreeElement::WrapNode(JSContext* aCx,
     28                                   JS::Handle<JSObject*> aGivenProto) {
     29  return XULTreeElement_Binding::Wrap(aCx, this, aGivenProto);
     30 }
     31 
     32 void XULTreeElement::UnbindFromTree(UnbindContext& aContext) {
     33  // Drop the view's ref to us.
     34  if (mView) {
     35    nsCOMPtr<nsITreeSelection> sel;
     36    mView->GetSelection(getter_AddRefs(sel));
     37    if (sel) {
     38      sel->SetTree(nullptr);
     39    }
     40    mView->SetTree(nullptr);  // Break the circular ref between the view and us.
     41  }
     42  mView = nullptr;
     43 
     44  nsXULElement::UnbindFromTree(aContext);
     45 }
     46 
     47 void XULTreeElement::DestroyContent() {
     48  // Drop the view's ref to us.
     49  if (mView) {
     50    nsCOMPtr<nsITreeSelection> sel;
     51    mView->GetSelection(getter_AddRefs(sel));
     52    if (sel) {
     53      sel->SetTree(nullptr);
     54    }
     55    mView->SetTree(nullptr);  // Break the circular ref between the view and us.
     56  }
     57  mView = nullptr;
     58 
     59  nsXULElement::DestroyContent();
     60 }
     61 
     62 static nsIContent* FindBodyElement(nsIContent* aParent) {
     63  mozilla::dom::FlattenedChildIterator iter(aParent);
     64  for (nsIContent* content = iter.GetNextChild(); content;
     65       content = iter.GetNextChild()) {
     66    mozilla::dom::NodeInfo* ni = content->NodeInfo();
     67    if (ni->Equals(nsGkAtoms::treechildren, kNameSpaceID_XUL)) {
     68      return content;
     69    } else if (ni->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
     70      // There are nesting tree elements. Only the innermost should
     71      // find the treechilren.
     72      return nullptr;
     73    } else if (content->IsElement() &&
     74               !ni->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
     75      nsIContent* result = FindBodyElement(content);
     76      if (result) return result;
     77    }
     78  }
     79 
     80  return nullptr;
     81 }
     82 
     83 nsTreeBodyFrame* XULTreeElement::GetTreeBodyFrame(FlushType aFlushType) {
     84  MOZ_ASSERT(aFlushType == FlushType::Frames ||
     85             aFlushType == FlushType::Layout || aFlushType == FlushType::None);
     86  nsCOMPtr<nsIContent> kungFuDeathGrip = this;  // keep a reference
     87 
     88  // Make sure our frames are up to date, and layout as needed.  We
     89  // have to do this before checking for our cached mTreeBody, since
     90  // it might go away on style flush, and in any case if aFlushLayout
     91  // is true we need to make sure to flush no matter what.
     92  if (aFlushType != FlushType::None) {
     93    if (RefPtr<Document> doc = GetComposedDoc()) {
     94      doc->FlushPendingNotifications(aFlushType);
     95    }
     96  }
     97 
     98  if (mTreeBody) {
     99    // Have one cached already.
    100    return mTreeBody;
    101  }
    102 
    103  if (nsCOMPtr<nsIContent> tree = FindBodyElement(this)) {
    104    mTreeBody = do_QueryFrame(tree->GetPrimaryFrame());
    105  }
    106 
    107  return mTreeBody;
    108 }
    109 
    110 already_AddRefed<nsITreeView> XULTreeElement::GetView(FlushType aFlushType) {
    111  if (!mTreeBody) {
    112    if (!GetTreeBodyFrame(aFlushType)) {
    113      return nullptr;
    114    }
    115 
    116    if (mView) {
    117      nsCOMPtr<nsITreeView> view;
    118      // Our new frame needs to initialise itself
    119      mTreeBody->GetView(getter_AddRefs(view));
    120      return view.forget();
    121    }
    122  }
    123  if (!mView) {
    124    // No tree builder, create a tree content view.
    125    if (NS_FAILED(NS_NewTreeContentView(getter_AddRefs(mView)))) {
    126      return nullptr;
    127    }
    128 
    129    // Initialise the frame and view
    130    mTreeBody->SetView(mView);
    131  }
    132 
    133  return do_AddRef(mView);
    134 }
    135 
    136 void XULTreeElement::SetView(nsITreeView* aView, CallerType aCallerType,
    137                             ErrorResult& aRv) {
    138  if (aCallerType != CallerType::System) {
    139    // Don't trust views coming from random places.
    140    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    141    return;
    142  }
    143 
    144  mView = aView;
    145  nsTreeBodyFrame* body = GetTreeBodyFrame();
    146  if (body) {
    147    body->SetView(aView);
    148  }
    149 }
    150 
    151 bool XULTreeElement::Focused() {
    152  nsTreeBodyFrame* body = GetTreeBodyFrame();
    153  if (body) {
    154    return body->GetFocused();
    155  }
    156  return false;
    157 }
    158 
    159 void XULTreeElement::SetFocused(bool aFocused) {
    160  nsTreeBodyFrame* body = GetTreeBodyFrame();
    161  if (body) {
    162    body->SetFocused(aFocused);
    163  }
    164 }
    165 
    166 already_AddRefed<Element> XULTreeElement::GetTreeBody() {
    167  nsTreeBodyFrame* body = GetTreeBodyFrame();
    168  if (body) {
    169    nsCOMPtr<Element> element;
    170    body->GetTreeBody(getter_AddRefs(element));
    171    return element.forget();
    172  }
    173 
    174  return nullptr;
    175 }
    176 
    177 already_AddRefed<nsTreeColumns> XULTreeElement::GetColumns(
    178    FlushType aFlushType) {
    179  if (nsTreeBodyFrame* body = GetTreeBodyFrame(aFlushType)) {
    180    return body->Columns();
    181  }
    182  return nullptr;
    183 }
    184 
    185 int32_t XULTreeElement::RowHeight() {
    186  nsTreeBodyFrame* body = GetTreeBodyFrame();
    187  if (body) {
    188    return body->RowHeight();
    189  }
    190  return 0;
    191 }
    192 
    193 int32_t XULTreeElement::RowWidth() {
    194  nsTreeBodyFrame* body = GetTreeBodyFrame();
    195  if (body) {
    196    return body->RowWidth();
    197  }
    198  return 0;
    199 }
    200 
    201 int32_t XULTreeElement::GetFirstVisibleRow() {
    202  nsTreeBodyFrame* body = GetTreeBodyFrame();
    203  if (body) {
    204    return body->FirstVisibleRow();
    205  }
    206  return 0;
    207 }
    208 
    209 int32_t XULTreeElement::GetLastVisibleRow() {
    210  nsTreeBodyFrame* body = GetTreeBodyFrame();
    211  if (body) {
    212    return body->LastVisibleRow();
    213  }
    214  return 0;
    215 }
    216 
    217 int32_t XULTreeElement::GetPageLength() {
    218  nsTreeBodyFrame* body = GetTreeBodyFrame();
    219  if (body) {
    220    return body->PageLength();
    221  }
    222  return 0;
    223 }
    224 
    225 void XULTreeElement::EnsureRowIsVisible(int32_t aRow) {
    226  nsTreeBodyFrame* body = GetTreeBodyFrame();
    227  if (body) {
    228    body->EnsureRowIsVisible(aRow);
    229  }
    230 }
    231 
    232 void XULTreeElement::EnsureCellIsVisible(int32_t aRow, nsTreeColumn* aCol,
    233                                         ErrorResult& aRv) {
    234  nsTreeBodyFrame* body = GetTreeBodyFrame();
    235  if (body) {
    236    nsresult rv = body->EnsureCellIsVisible(aRow, aCol);
    237    if (NS_FAILED(rv)) {
    238      aRv.Throw(rv);
    239    }
    240  }
    241 }
    242 
    243 void XULTreeElement::ScrollToRow(int32_t aRow) {
    244  nsTreeBodyFrame* body = GetTreeBodyFrame(FlushType::Layout);
    245  if (!body) {
    246    return;
    247  }
    248 
    249  body->ScrollToRow(aRow);
    250 }
    251 
    252 void XULTreeElement::ScrollByLines(int32_t aNumLines) {
    253  nsTreeBodyFrame* body = GetTreeBodyFrame();
    254  if (!body) {
    255    return;
    256  }
    257  body->ScrollByLines(aNumLines);
    258 }
    259 
    260 void XULTreeElement::ScrollByPages(int32_t aNumPages) {
    261  nsTreeBodyFrame* body = GetTreeBodyFrame();
    262  if (body) {
    263    body->ScrollByPages(aNumPages);
    264  }
    265 }
    266 
    267 void XULTreeElement::Invalidate() {
    268  nsTreeBodyFrame* body = GetTreeBodyFrame();
    269  if (body) {
    270    body->Invalidate();
    271  }
    272 }
    273 
    274 void XULTreeElement::InvalidateColumn(nsTreeColumn* aCol) {
    275  nsTreeBodyFrame* body = GetTreeBodyFrame();
    276  if (body) {
    277    body->InvalidateColumn(aCol);
    278  }
    279 }
    280 
    281 void XULTreeElement::InvalidateRow(int32_t aIndex) {
    282  nsTreeBodyFrame* body = GetTreeBodyFrame();
    283  if (body) {
    284    body->InvalidateRow(aIndex);
    285  }
    286 }
    287 
    288 void XULTreeElement::InvalidateCell(int32_t aRow, nsTreeColumn* aCol) {
    289  nsTreeBodyFrame* body = GetTreeBodyFrame();
    290  if (body) {
    291    body->InvalidateCell(aRow, aCol);
    292  }
    293 }
    294 
    295 void XULTreeElement::InvalidateRange(int32_t aStart, int32_t aEnd) {
    296  nsTreeBodyFrame* body = GetTreeBodyFrame();
    297  if (body) {
    298    body->InvalidateRange(aStart, aEnd);
    299  }
    300 }
    301 
    302 int32_t XULTreeElement::GetRowAt(int32_t x, int32_t y) {
    303  nsTreeBodyFrame* body = GetTreeBodyFrame();
    304  if (!body) {
    305    return 0;
    306  }
    307  return body->GetRowAt(x, y);
    308 }
    309 
    310 void XULTreeElement::GetCellAt(int32_t aX, int32_t aY, TreeCellInfo& aRetVal,
    311                               ErrorResult& aRv) {
    312  aRetVal.mRow = 0;
    313  aRetVal.mCol = nullptr;
    314 
    315  nsTreeBodyFrame* body = GetTreeBodyFrame();
    316  if (body) {
    317    nsAutoCString element;
    318    body->GetCellAt(aX, aY, &aRetVal.mRow, getter_AddRefs(aRetVal.mCol),
    319                    element);
    320    CopyUTF8toUTF16(element, aRetVal.mChildElt);
    321  }
    322 }
    323 
    324 nsIntRect XULTreeElement::GetCoordsForCellItem(int32_t aRow, nsTreeColumn* aCol,
    325                                               const nsAString& aElement,
    326                                               nsresult& rv) {
    327  rv = NS_OK;
    328  nsIntRect rect;
    329 
    330  nsTreeBodyFrame* body = GetTreeBodyFrame();
    331  NS_ConvertUTF16toUTF8 element(aElement);
    332  if (body) {
    333    rv = body->GetCoordsForCellItem(aRow, aCol, element, &rect.x, &rect.y,
    334                                    &rect.width, &rect.height);
    335  }
    336 
    337  return rect;
    338 }
    339 
    340 already_AddRefed<DOMRect> XULTreeElement::GetCoordsForCellItem(
    341    int32_t aRow, nsTreeColumn& aCol, const nsAString& aElement,
    342    ErrorResult& aRv) {
    343  nsresult rv;
    344  nsIntRect rect = GetCoordsForCellItem(aRow, &aCol, aElement, rv);
    345  aRv = rv;
    346 
    347  RefPtr<DOMRect> domRect = new DOMRect(ToSupports(OwnerDoc()), rect.x, rect.y,
    348                                        rect.width, rect.height);
    349  return domRect.forget();
    350 }
    351 
    352 bool XULTreeElement::IsCellCropped(int32_t aRow, nsTreeColumn* aCol,
    353                                   ErrorResult& aRv) {
    354  bool cropped = false;
    355 
    356  nsTreeBodyFrame* body = GetTreeBodyFrame();
    357  if (body) {
    358    aRv = body->IsCellCropped(aRow, aCol, &cropped);
    359  }
    360 
    361  return cropped;
    362 }
    363 
    364 void XULTreeElement::RowCountChanged(int32_t aIndex, int32_t aDelta) {
    365  nsTreeBodyFrame* body = GetTreeBodyFrame();
    366  if (body) {
    367    body->RowCountChanged(aIndex, aDelta);
    368  }
    369 }
    370 
    371 void XULTreeElement::BeginUpdateBatch() {
    372  nsTreeBodyFrame* body = GetTreeBodyFrame();
    373  if (body) {
    374    body->BeginUpdateBatch();
    375  }
    376 }
    377 
    378 void XULTreeElement::EndUpdateBatch() {
    379  nsTreeBodyFrame* body = GetTreeBodyFrame();
    380  if (body) {
    381    body->EndUpdateBatch();
    382  }
    383 }
    384 
    385 void XULTreeElement::ClearStyleAndImageCaches() {
    386  nsTreeBodyFrame* body = GetTreeBodyFrame();
    387  if (body) {
    388    body->ClearStyleAndImageCaches();
    389  }
    390 }
    391 
    392 void XULTreeElement::RemoveImageCacheEntry(int32_t aRowIndex,
    393                                           nsTreeColumn& aCol,
    394                                           ErrorResult& aRv) {
    395  if (NS_WARN_IF(aRowIndex < 0)) {
    396    aRv.Throw(NS_ERROR_INVALID_ARG);
    397    return;
    398  }
    399  nsTreeBodyFrame* body = GetTreeBodyFrame();
    400  if (body) {
    401    body->RemoveImageCacheEntry(aRowIndex, &aCol);
    402  }
    403 }
    404 
    405 nsScrollbarFrame* FindScrollbar(const XULTreeElement* aTree) {
    406  auto* shadow = aTree->GetShadowRoot();
    407  if (!shadow) {
    408    return nullptr;
    409  }
    410  for (nsINode* cur = shadow; cur; cur = cur->GetNextNode(shadow)) {
    411    if (cur->IsXULElement(nsGkAtoms::scrollbar)) {
    412      return do_QueryFrame(cur->AsElement()->GetPrimaryFrame());
    413    }
    414  }
    415  return nullptr;
    416 }
    417 
    418 int32_t XULTreeElement::ScrollbarPosition() const {
    419  if (auto* sb = FindScrollbar(this)) {
    420    return sb->GetCurPos();
    421  }
    422  return 0;
    423 }
    424 
    425 int32_t XULTreeElement::ScrollbarMaxPosition() const {
    426  if (auto* sb = FindScrollbar(this)) {
    427    return sb->GetMaxPos();
    428  }
    429  return 0;
    430 }
    431 
    432 }  // namespace mozilla::dom