layout/xul/tree/nsTreeBoxObject.cpp

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsTreeBoxObject.h"
michael@0 7 #include "nsCOMPtr.h"
michael@0 8 #include "nsIDOMXULElement.h"
michael@0 9 #include "nsIXULTemplateBuilder.h"
michael@0 10 #include "nsTreeContentView.h"
michael@0 11 #include "nsITreeSelection.h"
michael@0 12 #include "ChildIterator.h"
michael@0 13 #include "nsContentUtils.h"
michael@0 14 #include "nsError.h"
michael@0 15 #include "nsTreeBodyFrame.h"
michael@0 16
michael@0 17 NS_IMPL_CYCLE_COLLECTION(nsTreeBoxObject, mView)
michael@0 18
michael@0 19 NS_IMPL_ADDREF_INHERITED(nsTreeBoxObject, nsBoxObject)
michael@0 20 NS_IMPL_RELEASE_INHERITED(nsTreeBoxObject, nsBoxObject)
michael@0 21
michael@0 22 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsTreeBoxObject)
michael@0 23 NS_INTERFACE_MAP_ENTRY(nsITreeBoxObject)
michael@0 24 NS_INTERFACE_MAP_END_INHERITING(nsBoxObject)
michael@0 25
michael@0 26 void
michael@0 27 nsTreeBoxObject::Clear()
michael@0 28 {
michael@0 29 ClearCachedValues();
michael@0 30
michael@0 31 // Drop the view's ref to us.
michael@0 32 if (mView) {
michael@0 33 nsCOMPtr<nsITreeSelection> sel;
michael@0 34 mView->GetSelection(getter_AddRefs(sel));
michael@0 35 if (sel)
michael@0 36 sel->SetTree(nullptr);
michael@0 37 mView->SetTree(nullptr); // Break the circular ref between the view and us.
michael@0 38 }
michael@0 39 mView = nullptr;
michael@0 40
michael@0 41 nsBoxObject::Clear();
michael@0 42 }
michael@0 43
michael@0 44
michael@0 45 nsTreeBoxObject::nsTreeBoxObject()
michael@0 46 : mTreeBody(nullptr)
michael@0 47 {
michael@0 48 }
michael@0 49
michael@0 50 nsTreeBoxObject::~nsTreeBoxObject()
michael@0 51 {
michael@0 52 /* destructor code */
michael@0 53 }
michael@0 54
michael@0 55 static nsIContent* FindBodyElement(nsIContent* aParent)
michael@0 56 {
michael@0 57 mozilla::dom::FlattenedChildIterator iter(aParent);
michael@0 58 for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) {
michael@0 59 nsINodeInfo *ni = content->NodeInfo();
michael@0 60 if (ni->Equals(nsGkAtoms::treechildren, kNameSpaceID_XUL)) {
michael@0 61 return content;
michael@0 62 } else if (ni->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
michael@0 63 // There are nesting tree elements. Only the innermost should
michael@0 64 // find the treechilren.
michael@0 65 return nullptr;
michael@0 66 } else if (content->IsElement() &&
michael@0 67 !ni->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
michael@0 68 nsIContent* result = FindBodyElement(content);
michael@0 69 if (result)
michael@0 70 return result;
michael@0 71 }
michael@0 72 }
michael@0 73
michael@0 74 return nullptr;
michael@0 75 }
michael@0 76
michael@0 77 nsTreeBodyFrame*
michael@0 78 nsTreeBoxObject::GetTreeBody(bool aFlushLayout)
michael@0 79 {
michael@0 80 // Make sure our frames are up to date, and layout as needed. We
michael@0 81 // have to do this before checking for our cached mTreeBody, since
michael@0 82 // it might go away on style flush, and in any case if aFlushLayout
michael@0 83 // is true we need to make sure to flush no matter what.
michael@0 84 // XXXbz except that flushing style when we were not asked to flush
michael@0 85 // layout here breaks things. See bug 585123.
michael@0 86 nsIFrame* frame;
michael@0 87 if (aFlushLayout) {
michael@0 88 frame = GetFrame(aFlushLayout);
michael@0 89 if (!frame)
michael@0 90 return nullptr;
michael@0 91 }
michael@0 92
michael@0 93 if (mTreeBody) {
michael@0 94 // Have one cached already.
michael@0 95 return mTreeBody;
michael@0 96 }
michael@0 97
michael@0 98 if (!aFlushLayout) {
michael@0 99 frame = GetFrame(aFlushLayout);
michael@0 100 if (!frame)
michael@0 101 return nullptr;
michael@0 102 }
michael@0 103
michael@0 104 // Iterate over our content model children looking for the body.
michael@0 105 nsCOMPtr<nsIContent> content = FindBodyElement(frame->GetContent());
michael@0 106 if (!content)
michael@0 107 return nullptr;
michael@0 108
michael@0 109 frame = content->GetPrimaryFrame();
michael@0 110 if (!frame)
michael@0 111 return nullptr;
michael@0 112
michael@0 113 // Make sure that the treebodyframe has a pointer to |this|.
michael@0 114 nsTreeBodyFrame *treeBody = do_QueryFrame(frame);
michael@0 115 NS_ENSURE_TRUE(treeBody && treeBody->GetTreeBoxObject() == this, nullptr);
michael@0 116
michael@0 117 mTreeBody = treeBody;
michael@0 118 return mTreeBody;
michael@0 119 }
michael@0 120
michael@0 121 NS_IMETHODIMP nsTreeBoxObject::GetView(nsITreeView * *aView)
michael@0 122 {
michael@0 123 if (!mTreeBody) {
michael@0 124 if (!GetTreeBody()) {
michael@0 125 // Don't return an uninitialised view
michael@0 126 *aView = nullptr;
michael@0 127 return NS_OK;
michael@0 128 }
michael@0 129
michael@0 130 if (mView)
michael@0 131 // Our new frame needs to initialise itself
michael@0 132 return mTreeBody->GetView(aView);
michael@0 133 }
michael@0 134 if (!mView) {
michael@0 135 nsCOMPtr<nsIDOMXULElement> xulele = do_QueryInterface(mContent);
michael@0 136 if (xulele) {
michael@0 137 // See if there is a XUL tree builder associated with the element
michael@0 138 nsCOMPtr<nsIXULTemplateBuilder> builder;
michael@0 139 xulele->GetBuilder(getter_AddRefs(builder));
michael@0 140 mView = do_QueryInterface(builder);
michael@0 141
michael@0 142 if (!mView) {
michael@0 143 // No tree builder, create a tree content view.
michael@0 144 nsresult rv = NS_NewTreeContentView(getter_AddRefs(mView));
michael@0 145 NS_ENSURE_SUCCESS(rv, rv);
michael@0 146 }
michael@0 147
michael@0 148 // Initialise the frame and view
michael@0 149 mTreeBody->SetView(mView);
michael@0 150 }
michael@0 151 }
michael@0 152 NS_IF_ADDREF(*aView = mView);
michael@0 153 return NS_OK;
michael@0 154 }
michael@0 155
michael@0 156 static bool
michael@0 157 CanTrustView(nsISupports* aValue)
michael@0 158 {
michael@0 159 // Untrusted content is only allowed to specify known-good views
michael@0 160 if (nsContentUtils::IsCallerChrome())
michael@0 161 return true;
michael@0 162 nsCOMPtr<nsINativeTreeView> nativeTreeView = do_QueryInterface(aValue);
michael@0 163 if (!nativeTreeView || NS_FAILED(nativeTreeView->EnsureNative())) {
michael@0 164 // XXX ERRMSG need a good error here for developers
michael@0 165 return false;
michael@0 166 }
michael@0 167 return true;
michael@0 168 }
michael@0 169
michael@0 170 NS_IMETHODIMP nsTreeBoxObject::SetView(nsITreeView * aView)
michael@0 171 {
michael@0 172 if (!CanTrustView(aView))
michael@0 173 return NS_ERROR_DOM_SECURITY_ERR;
michael@0 174
michael@0 175 mView = aView;
michael@0 176 nsTreeBodyFrame* body = GetTreeBody();
michael@0 177 if (body)
michael@0 178 body->SetView(aView);
michael@0 179
michael@0 180 return NS_OK;
michael@0 181 }
michael@0 182
michael@0 183 NS_IMETHODIMP nsTreeBoxObject::GetFocused(bool* aFocused)
michael@0 184 {
michael@0 185 *aFocused = false;
michael@0 186 nsTreeBodyFrame* body = GetTreeBody();
michael@0 187 if (body)
michael@0 188 return body->GetFocused(aFocused);
michael@0 189 return NS_OK;
michael@0 190 }
michael@0 191
michael@0 192 NS_IMETHODIMP nsTreeBoxObject::SetFocused(bool aFocused)
michael@0 193 {
michael@0 194 nsTreeBodyFrame* body = GetTreeBody();
michael@0 195 if (body)
michael@0 196 return body->SetFocused(aFocused);
michael@0 197 return NS_OK;
michael@0 198 }
michael@0 199
michael@0 200 NS_IMETHODIMP nsTreeBoxObject::GetTreeBody(nsIDOMElement** aElement)
michael@0 201 {
michael@0 202 *aElement = nullptr;
michael@0 203 nsTreeBodyFrame* body = GetTreeBody();
michael@0 204 if (body)
michael@0 205 return body->GetTreeBody(aElement);
michael@0 206 return NS_OK;
michael@0 207 }
michael@0 208
michael@0 209 NS_IMETHODIMP nsTreeBoxObject::GetColumns(nsITreeColumns** aColumns)
michael@0 210 {
michael@0 211 *aColumns = nullptr;
michael@0 212 nsTreeBodyFrame* body = GetTreeBody();
michael@0 213 if (body)
michael@0 214 *aColumns = body->Columns().take();
michael@0 215 return NS_OK;
michael@0 216 }
michael@0 217
michael@0 218 NS_IMETHODIMP nsTreeBoxObject::GetRowHeight(int32_t* aRowHeight)
michael@0 219 {
michael@0 220 *aRowHeight = 0;
michael@0 221 nsTreeBodyFrame* body = GetTreeBody();
michael@0 222 if (body)
michael@0 223 return body->GetRowHeight(aRowHeight);
michael@0 224 return NS_OK;
michael@0 225 }
michael@0 226
michael@0 227 NS_IMETHODIMP nsTreeBoxObject::GetRowWidth(int32_t *aRowWidth)
michael@0 228 {
michael@0 229 *aRowWidth = 0;
michael@0 230 nsTreeBodyFrame* body = GetTreeBody();
michael@0 231 if (body)
michael@0 232 return body->GetRowWidth(aRowWidth);
michael@0 233 return NS_OK;
michael@0 234 }
michael@0 235
michael@0 236 NS_IMETHODIMP nsTreeBoxObject::GetFirstVisibleRow(int32_t *aFirstVisibleRow)
michael@0 237 {
michael@0 238 *aFirstVisibleRow = 0;
michael@0 239 nsTreeBodyFrame* body = GetTreeBody();
michael@0 240 if (body)
michael@0 241 *aFirstVisibleRow = body->FirstVisibleRow();
michael@0 242 return NS_OK;
michael@0 243 }
michael@0 244
michael@0 245 NS_IMETHODIMP nsTreeBoxObject::GetLastVisibleRow(int32_t *aLastVisibleRow)
michael@0 246 {
michael@0 247 *aLastVisibleRow = 0;
michael@0 248 nsTreeBodyFrame* body = GetTreeBody();
michael@0 249 if (body)
michael@0 250 *aLastVisibleRow = body->LastVisibleRow();
michael@0 251 return NS_OK;
michael@0 252 }
michael@0 253
michael@0 254 NS_IMETHODIMP nsTreeBoxObject::GetHorizontalPosition(int32_t *aHorizontalPosition)
michael@0 255 {
michael@0 256 *aHorizontalPosition = 0;
michael@0 257 nsTreeBodyFrame* body = GetTreeBody();
michael@0 258 if (body)
michael@0 259 return body->GetHorizontalPosition(aHorizontalPosition);
michael@0 260 return NS_OK;
michael@0 261 }
michael@0 262
michael@0 263 NS_IMETHODIMP nsTreeBoxObject::GetPageLength(int32_t *aPageLength)
michael@0 264 {
michael@0 265 *aPageLength = 0;
michael@0 266 nsTreeBodyFrame* body = GetTreeBody();
michael@0 267 if (body)
michael@0 268 *aPageLength = body->PageLength();
michael@0 269 return NS_OK;
michael@0 270 }
michael@0 271
michael@0 272 NS_IMETHODIMP nsTreeBoxObject::GetSelectionRegion(nsIScriptableRegion **aRegion)
michael@0 273 {
michael@0 274 *aRegion = nullptr;
michael@0 275 nsTreeBodyFrame* body = GetTreeBody();
michael@0 276 if (body)
michael@0 277 return body->GetSelectionRegion(aRegion);
michael@0 278 return NS_OK;
michael@0 279 }
michael@0 280
michael@0 281 NS_IMETHODIMP
michael@0 282 nsTreeBoxObject::EnsureRowIsVisible(int32_t aRow)
michael@0 283 {
michael@0 284 nsTreeBodyFrame* body = GetTreeBody();
michael@0 285 if (body)
michael@0 286 return body->EnsureRowIsVisible(aRow);
michael@0 287 return NS_OK;
michael@0 288 }
michael@0 289
michael@0 290 NS_IMETHODIMP
michael@0 291 nsTreeBoxObject::EnsureCellIsVisible(int32_t aRow, nsITreeColumn* aCol)
michael@0 292 {
michael@0 293 nsTreeBodyFrame* body = GetTreeBody();
michael@0 294 if (body)
michael@0 295 return body->EnsureCellIsVisible(aRow, aCol);
michael@0 296 return NS_OK;
michael@0 297 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 298 }
michael@0 299
michael@0 300 NS_IMETHODIMP
michael@0 301 nsTreeBoxObject::ScrollToRow(int32_t aRow)
michael@0 302 {
michael@0 303 nsTreeBodyFrame* body = GetTreeBody(true);
michael@0 304 if (body)
michael@0 305 return body->ScrollToRow(aRow);
michael@0 306 return NS_OK;
michael@0 307 }
michael@0 308
michael@0 309 NS_IMETHODIMP
michael@0 310 nsTreeBoxObject::ScrollByLines(int32_t aNumLines)
michael@0 311 {
michael@0 312 nsTreeBodyFrame* body = GetTreeBody();
michael@0 313 if (body)
michael@0 314 return body->ScrollByLines(aNumLines);
michael@0 315 return NS_OK;
michael@0 316 }
michael@0 317
michael@0 318 NS_IMETHODIMP
michael@0 319 nsTreeBoxObject::ScrollByPages(int32_t aNumPages)
michael@0 320 {
michael@0 321 nsTreeBodyFrame* body = GetTreeBody();
michael@0 322 if (body)
michael@0 323 return body->ScrollByPages(aNumPages);
michael@0 324 return NS_OK;
michael@0 325 }
michael@0 326
michael@0 327 NS_IMETHODIMP
michael@0 328 nsTreeBoxObject::ScrollToCell(int32_t aRow, nsITreeColumn* aCol)
michael@0 329 {
michael@0 330 nsTreeBodyFrame* body = GetTreeBody();
michael@0 331 if (body)
michael@0 332 return body->ScrollToCell(aRow, aCol);
michael@0 333 return NS_OK;
michael@0 334 }
michael@0 335
michael@0 336 NS_IMETHODIMP
michael@0 337 nsTreeBoxObject::ScrollToColumn(nsITreeColumn* aCol)
michael@0 338 {
michael@0 339 nsTreeBodyFrame* body = GetTreeBody();
michael@0 340 if (body)
michael@0 341 return body->ScrollToColumn(aCol);
michael@0 342 return NS_OK;
michael@0 343 }
michael@0 344
michael@0 345 NS_IMETHODIMP
michael@0 346 nsTreeBoxObject::ScrollToHorizontalPosition(int32_t aHorizontalPosition)
michael@0 347 {
michael@0 348 nsTreeBodyFrame* body = GetTreeBody();
michael@0 349 if (body)
michael@0 350 return body->ScrollToHorizontalPosition(aHorizontalPosition);
michael@0 351 return NS_OK;
michael@0 352 }
michael@0 353
michael@0 354 NS_IMETHODIMP nsTreeBoxObject::Invalidate()
michael@0 355 {
michael@0 356 nsTreeBodyFrame* body = GetTreeBody();
michael@0 357 if (body)
michael@0 358 return body->Invalidate();
michael@0 359 return NS_OK;
michael@0 360 }
michael@0 361
michael@0 362 NS_IMETHODIMP nsTreeBoxObject::InvalidateColumn(nsITreeColumn* aCol)
michael@0 363 {
michael@0 364 nsTreeBodyFrame* body = GetTreeBody();
michael@0 365 if (body)
michael@0 366 return body->InvalidateColumn(aCol);
michael@0 367 return NS_OK;
michael@0 368 }
michael@0 369
michael@0 370 NS_IMETHODIMP nsTreeBoxObject::InvalidateRow(int32_t aIndex)
michael@0 371 {
michael@0 372 nsTreeBodyFrame* body = GetTreeBody();
michael@0 373 if (body)
michael@0 374 return body->InvalidateRow(aIndex);
michael@0 375 return NS_OK;
michael@0 376 }
michael@0 377
michael@0 378 NS_IMETHODIMP nsTreeBoxObject::InvalidateCell(int32_t aRow, nsITreeColumn* aCol)
michael@0 379 {
michael@0 380 nsTreeBodyFrame* body = GetTreeBody();
michael@0 381 if (body)
michael@0 382 return body->InvalidateCell(aRow, aCol);
michael@0 383 return NS_OK;
michael@0 384 }
michael@0 385
michael@0 386 NS_IMETHODIMP nsTreeBoxObject::InvalidateRange(int32_t aStart, int32_t aEnd)
michael@0 387 {
michael@0 388 nsTreeBodyFrame* body = GetTreeBody();
michael@0 389 if (body)
michael@0 390 return body->InvalidateRange(aStart, aEnd);
michael@0 391 return NS_OK;
michael@0 392 }
michael@0 393
michael@0 394 NS_IMETHODIMP nsTreeBoxObject::InvalidateColumnRange(int32_t aStart, int32_t aEnd, nsITreeColumn* aCol)
michael@0 395 {
michael@0 396 nsTreeBodyFrame* body = GetTreeBody();
michael@0 397 if (body)
michael@0 398 return body->InvalidateColumnRange(aStart, aEnd, aCol);
michael@0 399 return NS_OK;
michael@0 400 }
michael@0 401
michael@0 402 NS_IMETHODIMP nsTreeBoxObject::GetRowAt(int32_t x, int32_t y, int32_t *aRow)
michael@0 403 {
michael@0 404 *aRow = 0;
michael@0 405 nsTreeBodyFrame* body = GetTreeBody();
michael@0 406 if (body)
michael@0 407 return body->GetRowAt(x, y, aRow);
michael@0 408 return NS_OK;
michael@0 409 }
michael@0 410
michael@0 411 NS_IMETHODIMP nsTreeBoxObject::GetCellAt(int32_t aX, int32_t aY, int32_t *aRow, nsITreeColumn** aCol,
michael@0 412 nsACString& aChildElt)
michael@0 413 {
michael@0 414 *aRow = 0;
michael@0 415 *aCol = nullptr;
michael@0 416 nsTreeBodyFrame* body = GetTreeBody();
michael@0 417 if (body)
michael@0 418 return body->GetCellAt(aX, aY, aRow, aCol, aChildElt);
michael@0 419 return NS_OK;
michael@0 420 }
michael@0 421
michael@0 422 NS_IMETHODIMP
michael@0 423 nsTreeBoxObject::GetCoordsForCellItem(int32_t aRow, nsITreeColumn* aCol, const nsACString& aElement,
michael@0 424 int32_t *aX, int32_t *aY, int32_t *aWidth, int32_t *aHeight)
michael@0 425 {
michael@0 426 *aX = *aY = *aWidth = *aHeight = 0;
michael@0 427 nsTreeBodyFrame* body = GetTreeBody();
michael@0 428 if (body)
michael@0 429 return body->GetCoordsForCellItem(aRow, aCol, aElement, aX, aY, aWidth, aHeight);
michael@0 430 return NS_OK;
michael@0 431 }
michael@0 432
michael@0 433 NS_IMETHODIMP
michael@0 434 nsTreeBoxObject::IsCellCropped(int32_t aRow, nsITreeColumn* aCol, bool *aIsCropped)
michael@0 435 {
michael@0 436 *aIsCropped = false;
michael@0 437 nsTreeBodyFrame* body = GetTreeBody();
michael@0 438 if (body)
michael@0 439 return body->IsCellCropped(aRow, aCol, aIsCropped);
michael@0 440 return NS_OK;
michael@0 441 }
michael@0 442
michael@0 443 NS_IMETHODIMP nsTreeBoxObject::RowCountChanged(int32_t aIndex, int32_t aDelta)
michael@0 444 {
michael@0 445 nsTreeBodyFrame* body = GetTreeBody();
michael@0 446 if (body)
michael@0 447 return body->RowCountChanged(aIndex, aDelta);
michael@0 448 return NS_OK;
michael@0 449 }
michael@0 450
michael@0 451 NS_IMETHODIMP nsTreeBoxObject::BeginUpdateBatch()
michael@0 452 {
michael@0 453 nsTreeBodyFrame* body = GetTreeBody();
michael@0 454 if (body)
michael@0 455 return body->BeginUpdateBatch();
michael@0 456 return NS_OK;
michael@0 457 }
michael@0 458
michael@0 459 NS_IMETHODIMP nsTreeBoxObject::EndUpdateBatch()
michael@0 460 {
michael@0 461 nsTreeBodyFrame* body = GetTreeBody();
michael@0 462 if (body)
michael@0 463 return body->EndUpdateBatch();
michael@0 464 return NS_OK;
michael@0 465 }
michael@0 466
michael@0 467 NS_IMETHODIMP nsTreeBoxObject::ClearStyleAndImageCaches()
michael@0 468 {
michael@0 469 nsTreeBodyFrame* body = GetTreeBody();
michael@0 470 if (body)
michael@0 471 return body->ClearStyleAndImageCaches();
michael@0 472 return NS_OK;
michael@0 473 }
michael@0 474
michael@0 475 void
michael@0 476 nsTreeBoxObject::ClearCachedValues()
michael@0 477 {
michael@0 478 mTreeBody = nullptr;
michael@0 479 }
michael@0 480
michael@0 481 // Creation Routine ///////////////////////////////////////////////////////////////////////
michael@0 482
michael@0 483 nsresult
michael@0 484 NS_NewTreeBoxObject(nsIBoxObject** aResult)
michael@0 485 {
michael@0 486 *aResult = new nsTreeBoxObject;
michael@0 487 if (!*aResult)
michael@0 488 return NS_ERROR_OUT_OF_MEMORY;
michael@0 489 NS_ADDREF(*aResult);
michael@0 490 return NS_OK;
michael@0 491 }
michael@0 492

mercurial