Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/xul/tree/TreeBoxObject.cpp
Line
Count
Source (jump to first uncovered line)
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/TreeBoxObject.h"
8
#include "nsCOMPtr.h"
9
#include "nsXULElement.h"
10
#include "nsTreeContentView.h"
11
#include "nsITreeSelection.h"
12
#include "ChildIterator.h"
13
#include "nsError.h"
14
#include "nsTreeBodyFrame.h"
15
#include "mozilla/dom/TreeBoxObjectBinding.h"
16
#include "mozilla/dom/DOMRect.h"
17
#include "mozilla/dom/BindingUtils.h"
18
#include "mozilla/dom/Element.h"
19
#include "mozilla/dom/ToJSValue.h"
20
21
namespace mozilla {
22
namespace dom {
23
24
NS_IMPL_CYCLE_COLLECTION_INHERITED(TreeBoxObject, BoxObject,
25
                                   mView)
26
27
NS_IMPL_ADDREF_INHERITED(TreeBoxObject, BoxObject)
28
NS_IMPL_RELEASE_INHERITED(TreeBoxObject, BoxObject)
29
30
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TreeBoxObject)
31
0
  NS_INTERFACE_MAP_ENTRY(nsITreeBoxObject)
32
0
NS_INTERFACE_MAP_END_INHERITING(BoxObject)
33
34
void
35
TreeBoxObject::Clear()
36
0
{
37
0
  ClearCachedValues();
38
0
39
0
  // Drop the view's ref to us.
40
0
  if (mView) {
41
0
    nsCOMPtr<nsITreeSelection> sel;
42
0
    mView->GetSelection(getter_AddRefs(sel));
43
0
    if (sel)
44
0
      sel->SetTree(nullptr);
45
0
    mView->SetTree(nullptr); // Break the circular ref between the view and us.
46
0
  }
47
0
  mView = nullptr;
48
0
49
0
  BoxObject::Clear();
50
0
}
51
52
53
TreeBoxObject::TreeBoxObject()
54
  : mTreeBody(nullptr)
55
0
{
56
0
}
57
58
TreeBoxObject::~TreeBoxObject()
59
0
{
60
0
}
61
62
static nsIContent* FindBodyElement(nsIContent* aParent)
63
0
{
64
0
  mozilla::dom::FlattenedChildIterator iter(aParent);
65
0
  for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) {
66
0
    mozilla::dom::NodeInfo *ni = content->NodeInfo();
67
0
    if (ni->Equals(nsGkAtoms::treechildren, kNameSpaceID_XUL)) {
68
0
      return content;
69
0
    } else if (ni->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
70
0
      // There are nesting tree elements. Only the innermost should
71
0
      // find the treechilren.
72
0
      return nullptr;
73
0
    } else if (content->IsElement() &&
74
0
               !ni->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
75
0
      nsIContent* result = FindBodyElement(content);
76
0
      if (result)
77
0
        return result;
78
0
    }
79
0
  }
80
0
81
0
  return nullptr;
82
0
}
83
84
nsTreeBodyFrame*
85
TreeBoxObject::GetTreeBodyFrame(bool aFlushLayout)
86
0
{
87
0
  // Make sure our frames are up to date, and layout as needed.  We
88
0
  // have to do this before checking for our cached mTreeBody, since
89
0
  // it might go away on style flush, and in any case if aFlushLayout
90
0
  // is true we need to make sure to flush no matter what.
91
0
  // XXXbz except that flushing style when we were not asked to flush
92
0
  // layout here breaks things.  See bug 585123.
93
0
  nsIFrame* frame = nullptr;
94
0
  if (aFlushLayout) {
95
0
    frame = GetFrame(aFlushLayout);
96
0
    if (!frame)
97
0
      return nullptr;
98
0
  }
99
0
100
0
  if (mTreeBody) {
101
0
    // Have one cached already.
102
0
    return mTreeBody;
103
0
  }
104
0
105
0
  if (!aFlushLayout) {
106
0
    frame = GetFrame(aFlushLayout);
107
0
    if (!frame)
108
0
      return nullptr;
109
0
  }
110
0
111
0
  // Iterate over our content model children looking for the body.
112
0
  nsCOMPtr<nsIContent> content = FindBodyElement(frame->GetContent());
113
0
  if (!content)
114
0
    return nullptr;
115
0
116
0
  frame = content->GetPrimaryFrame();
117
0
  if (!frame)
118
0
     return nullptr;
119
0
120
0
  // Make sure that the treebodyframe has a pointer to |this|.
121
0
  nsTreeBodyFrame *treeBody = do_QueryFrame(frame);
122
0
  NS_ENSURE_TRUE(treeBody && treeBody->GetTreeBoxObject() == this, nullptr);
123
0
124
0
  mTreeBody = treeBody;
125
0
  return mTreeBody;
126
0
}
127
128
NS_IMETHODIMP
129
TreeBoxObject::GetView(nsITreeView * *aView)
130
0
{
131
0
  if (!mTreeBody) {
132
0
    if (!GetTreeBodyFrame()) {
133
0
      // Don't return an uninitialised view
134
0
      *aView = nullptr;
135
0
      return NS_OK;
136
0
    }
137
0
138
0
    if (mView)
139
0
      // Our new frame needs to initialise itself
140
0
      return mTreeBody->GetView(aView);
141
0
  }
142
0
  if (!mView) {
143
0
    RefPtr<nsXULElement> xulele = nsXULElement::FromNodeOrNull(mContent);
144
0
    if (xulele) {
145
0
      // No tree builder, create a tree content view.
146
0
      nsresult rv = NS_NewTreeContentView(getter_AddRefs(mView));
147
0
      NS_ENSURE_SUCCESS(rv, rv);
148
0
149
0
      // Initialise the frame and view
150
0
      mTreeBody->SetView(mView);
151
0
    }
152
0
  }
153
0
  NS_IF_ADDREF(*aView = mView);
154
0
  return NS_OK;
155
0
}
156
157
already_AddRefed<nsITreeView>
158
TreeBoxObject::GetView(CallerType /* unused */)
159
0
{
160
0
  nsCOMPtr<nsITreeView> view;
161
0
  GetView(getter_AddRefs(view));
162
0
  return view.forget();
163
0
}
164
165
NS_IMETHODIMP
166
TreeBoxObject::SetView(nsITreeView* aView)
167
0
{
168
0
  ErrorResult rv;
169
0
  SetView(aView, CallerType::System, rv);
170
0
  return rv.StealNSResult();
171
0
}
172
173
void
174
TreeBoxObject::SetView(nsITreeView* aView, CallerType aCallerType,
175
                       ErrorResult& aRv)
176
0
{
177
0
  if (aCallerType != CallerType::System) {
178
0
    // Don't trust views coming from random places.
179
0
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
180
0
    return;
181
0
  }
182
0
183
0
  mView = aView;
184
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
185
0
  if (body)
186
0
    body->SetView(aView);
187
0
}
188
189
bool TreeBoxObject::Focused()
190
0
{
191
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
192
0
  if (body)
193
0
    return body->GetFocused();
194
0
  return false;
195
0
}
196
197
NS_IMETHODIMP TreeBoxObject::GetFocused(bool* aFocused)
198
0
{
199
0
  *aFocused = Focused();
200
0
  return NS_OK;
201
0
}
202
203
NS_IMETHODIMP TreeBoxObject::SetFocused(bool aFocused)
204
0
{
205
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
206
0
  if (body)
207
0
    return body->SetFocused(aFocused);
208
0
  return NS_OK;
209
0
}
210
211
NS_IMETHODIMP TreeBoxObject::GetTreeBody(Element** aElement)
212
0
{
213
0
  *aElement = nullptr;
214
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
215
0
  if (body)
216
0
    return body->GetTreeBody(aElement);
217
0
  return NS_OK;
218
0
}
219
220
already_AddRefed<Element>
221
TreeBoxObject::GetTreeBody()
222
0
{
223
0
  RefPtr<Element> el;
224
0
  GetTreeBody(getter_AddRefs(el));
225
0
  return el.forget();
226
0
}
227
228
already_AddRefed<nsTreeColumns>
229
TreeBoxObject::GetColumns()
230
0
{
231
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
232
0
  if (body)
233
0
    return body->Columns();
234
0
  return nullptr;
235
0
}
236
237
NS_IMETHODIMP TreeBoxObject::GetColumns(nsTreeColumns** aColumns)
238
0
{
239
0
  *aColumns = GetColumns().take();
240
0
  return NS_OK;
241
0
}
242
243
int32_t TreeBoxObject::RowHeight()
244
0
{
245
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
246
0
  if (body)
247
0
    return body->RowHeight();
248
0
  return 0;
249
0
}
250
251
int32_t TreeBoxObject::RowWidth()
252
0
{
253
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
254
0
  if (body)
255
0
    return body->RowWidth();
256
0
  return 0;
257
0
}
258
259
NS_IMETHODIMP TreeBoxObject::GetRowHeight(int32_t* aRowHeight)
260
0
{
261
0
  *aRowHeight = RowHeight();
262
0
  return NS_OK;
263
0
}
264
265
NS_IMETHODIMP TreeBoxObject::GetRowWidth(int32_t *aRowWidth)
266
0
{
267
0
  *aRowWidth = RowWidth();
268
0
  return NS_OK;
269
0
}
270
271
int32_t TreeBoxObject::GetFirstVisibleRow()
272
0
{
273
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
274
0
  if (body)
275
0
    return body->FirstVisibleRow();
276
0
  return 0;
277
0
}
278
279
NS_IMETHODIMP TreeBoxObject::GetFirstVisibleRow(int32_t *aFirstVisibleRow)
280
0
{
281
0
  *aFirstVisibleRow = GetFirstVisibleRow();
282
0
  return NS_OK;
283
0
}
284
285
int32_t TreeBoxObject::GetLastVisibleRow()
286
0
{
287
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
288
0
  if (body)
289
0
    return body->LastVisibleRow();
290
0
  return 0;
291
0
}
292
293
NS_IMETHODIMP TreeBoxObject::GetLastVisibleRow(int32_t *aLastVisibleRow)
294
0
{
295
0
  *aLastVisibleRow = GetLastVisibleRow();
296
0
  return NS_OK;
297
0
}
298
299
int32_t TreeBoxObject::HorizontalPosition()
300
0
{
301
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
302
0
  if (body)
303
0
    return body->GetHorizontalPosition();
304
0
  return 0;
305
0
}
306
307
int32_t TreeBoxObject::GetPageLength()
308
0
{
309
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
310
0
  if (body)
311
0
    return body->PageLength();
312
0
  return 0;
313
0
}
314
315
NS_IMETHODIMP
316
TreeBoxObject::EnsureRowIsVisible(int32_t aRow)
317
0
{
318
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
319
0
  if (body)
320
0
    return body->EnsureRowIsVisible(aRow);
321
0
  return NS_OK;
322
0
}
323
324
void
325
TreeBoxObject::EnsureCellIsVisible(int32_t aRow, nsTreeColumn* aCol, ErrorResult& aRv)
326
0
{
327
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
328
0
  if (body) {
329
0
    nsresult rv = body->EnsureCellIsVisible(aRow, aCol);
330
0
    if (NS_FAILED(rv)) {
331
0
      aRv.Throw(rv);
332
0
    }
333
0
  }
334
0
}
335
336
void
337
TreeBoxObject::ScrollToRow(int32_t aRow)
338
0
{
339
0
  nsTreeBodyFrame* body = GetTreeBodyFrame(true);
340
0
  if (!body) {
341
0
    return;
342
0
  }
343
0
344
0
  body->ScrollToRow(aRow);
345
0
}
346
347
void
348
TreeBoxObject::ScrollByLines(int32_t aNumLines)
349
0
{
350
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
351
0
  if (!body) {
352
0
    return;
353
0
  }
354
0
  body->ScrollByLines(aNumLines);
355
0
}
356
357
void
358
TreeBoxObject::ScrollByPages(int32_t aNumPages)
359
0
{
360
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
361
0
  if (body)
362
0
    body->ScrollByPages(aNumPages);
363
0
}
364
365
NS_IMETHODIMP TreeBoxObject::Invalidate()
366
0
{
367
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
368
0
  if (body)
369
0
    return body->Invalidate();
370
0
  return NS_OK;
371
0
}
372
373
NS_IMETHODIMP
374
TreeBoxObject::InvalidateColumn(nsTreeColumn* aCol)
375
0
{
376
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
377
0
  if (body)
378
0
    return body->InvalidateColumn(aCol);
379
0
  return NS_OK;
380
0
}
381
382
NS_IMETHODIMP
383
TreeBoxObject::InvalidateRow(int32_t aIndex)
384
0
{
385
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
386
0
  if (body)
387
0
    return body->InvalidateRow(aIndex);
388
0
  return NS_OK;
389
0
}
390
391
NS_IMETHODIMP
392
TreeBoxObject::InvalidateCell(int32_t aRow, nsTreeColumn* aCol)
393
0
{
394
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
395
0
  if (body)
396
0
    return body->InvalidateCell(aRow, aCol);
397
0
  return NS_OK;
398
0
}
399
400
NS_IMETHODIMP
401
TreeBoxObject::InvalidateRange(int32_t aStart, int32_t aEnd)
402
0
{
403
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
404
0
  if (body)
405
0
    return body->InvalidateRange(aStart, aEnd);
406
0
  return NS_OK;
407
0
}
408
409
int32_t
410
TreeBoxObject::GetRowAt(int32_t x, int32_t y)
411
0
{
412
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
413
0
  if (!body) {
414
0
    return 0;
415
0
  }
416
0
  return body->GetRowAt(x, y);
417
0
}
418
419
NS_IMETHODIMP
420
TreeBoxObject::GetCellAt(int32_t aX, int32_t aY, int32_t *aRow,
421
                         nsTreeColumn** aCol, nsAString& aChildElt)
422
0
{
423
0
  *aRow = 0;
424
0
  *aCol = nullptr;
425
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
426
0
  if (body) {
427
0
    nsAutoCString element;
428
0
    nsresult retval = body->GetCellAt(aX, aY, aRow, aCol, element);
429
0
    CopyUTF8toUTF16(element, aChildElt);
430
0
    return retval;
431
0
  }
432
0
  return NS_OK;
433
0
}
434
435
void
436
TreeBoxObject::GetCellAt(int32_t x, int32_t y, TreeCellInfo& aRetVal, ErrorResult& aRv)
437
0
{
438
0
  GetCellAt(x, y, &aRetVal.mRow, getter_AddRefs(aRetVal.mCol),
439
0
            aRetVal.mChildElt);
440
0
}
441
442
void
443
TreeBoxObject::GetCellAt(JSContext* cx,
444
                         int32_t x, int32_t y,
445
                         JS::Handle<JSObject*> rowOut,
446
                         JS::Handle<JSObject*> colOut,
447
                         JS::Handle<JSObject*> childEltOut,
448
                         ErrorResult& aRv)
449
0
{
450
0
  int32_t row;
451
0
  RefPtr<nsTreeColumn> col;
452
0
  nsAutoString childElt;
453
0
  GetCellAt(x, y, &row, getter_AddRefs(col), childElt);
454
0
455
0
  JS::Rooted<JS::Value> v(cx);
456
0
457
0
  if (!ToJSValue(cx, row, &v) ||
458
0
      !JS_SetProperty(cx, rowOut, "value", v)) {
459
0
    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
460
0
    return;
461
0
  }
462
0
  if (!dom::WrapObject(cx, col, &v) ||
463
0
      !JS_SetProperty(cx, colOut, "value", v)) {
464
0
    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
465
0
    return;
466
0
  }
467
0
  if (!ToJSValue(cx, childElt, &v) ||
468
0
      !JS_SetProperty(cx, childEltOut, "value", v)) {
469
0
    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
470
0
    return;
471
0
  }
472
0
}
473
474
NS_IMETHODIMP
475
TreeBoxObject::GetCoordsForCellItem(int32_t aRow, nsTreeColumn* aCol, const nsAString& aElement,
476
                                      int32_t *aX, int32_t *aY, int32_t *aWidth, int32_t *aHeight)
477
0
{
478
0
  *aX = *aY = *aWidth = *aHeight = 0;
479
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
480
0
  NS_ConvertUTF16toUTF8 element(aElement);
481
0
  if (body)
482
0
    return body->GetCoordsForCellItem(aRow, aCol, element, aX, aY, aWidth, aHeight);
483
0
  return NS_OK;
484
0
}
485
486
already_AddRefed<DOMRect>
487
TreeBoxObject::GetCoordsForCellItem(int32_t row, nsTreeColumn& col, const nsAString& element, ErrorResult& aRv)
488
0
{
489
0
  int32_t x, y, w, h;
490
0
  GetCoordsForCellItem(row, &col, element, &x, &y, &w, &h);
491
0
  RefPtr<DOMRect> rect = new DOMRect(mContent, x, y, w, h);
492
0
  return rect.forget();
493
0
}
494
495
void
496
TreeBoxObject::GetCoordsForCellItem(JSContext* cx,
497
                                    int32_t row,
498
                                    nsTreeColumn& col,
499
                                    const nsAString& element,
500
                                    JS::Handle<JSObject*> xOut,
501
                                    JS::Handle<JSObject*> yOut,
502
                                    JS::Handle<JSObject*> widthOut,
503
                                    JS::Handle<JSObject*> heightOut,
504
                                    ErrorResult& aRv)
505
0
{
506
0
  int32_t x, y, w, h;
507
0
  GetCoordsForCellItem(row, &col, element, &x, &y, &w, &h);
508
0
  JS::Rooted<JS::Value> v(cx, JS::Int32Value(x));
509
0
  if (!JS_SetProperty(cx, xOut, "value", v)) {
510
0
    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
511
0
    return;
512
0
  }
513
0
  v.setInt32(y);
514
0
  if (!JS_SetProperty(cx, yOut, "value", v)) {
515
0
    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
516
0
    return;
517
0
  }
518
0
  v.setInt32(w);
519
0
  if (!JS_SetProperty(cx, widthOut, "value", v)) {
520
0
    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
521
0
    return;
522
0
  }
523
0
  v.setInt32(h);
524
0
  if (!JS_SetProperty(cx, heightOut, "value", v)) {
525
0
    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
526
0
    return;
527
0
  }
528
0
}
529
530
NS_IMETHODIMP
531
TreeBoxObject::IsCellCropped(int32_t aRow, nsTreeColumn* aCol, bool *aIsCropped)
532
0
{
533
0
  *aIsCropped = false;
534
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
535
0
  if (body)
536
0
    return body->IsCellCropped(aRow, aCol, aIsCropped);
537
0
  return NS_OK;
538
0
}
539
540
bool
541
TreeBoxObject::IsCellCropped(int32_t row, nsTreeColumn* col, ErrorResult& aRv)
542
0
{
543
0
  bool ret;
544
0
  aRv = IsCellCropped(row, col, &ret);
545
0
  return ret;
546
0
}
547
548
NS_IMETHODIMP
549
TreeBoxObject::RowCountChanged(int32_t aIndex, int32_t aDelta)
550
0
{
551
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
552
0
  if (body)
553
0
    return body->RowCountChanged(aIndex, aDelta);
554
0
  return NS_OK;
555
0
}
556
557
NS_IMETHODIMP
558
TreeBoxObject::BeginUpdateBatch()
559
0
{
560
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
561
0
  if (body)
562
0
    return body->BeginUpdateBatch();
563
0
  return NS_OK;
564
0
}
565
566
NS_IMETHODIMP
567
TreeBoxObject::EndUpdateBatch()
568
0
{
569
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
570
0
  if (body)
571
0
    return body->EndUpdateBatch();
572
0
  return NS_OK;
573
0
}
574
575
NS_IMETHODIMP
576
TreeBoxObject::ClearStyleAndImageCaches()
577
0
{
578
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
579
0
  if (body)
580
0
    return body->ClearStyleAndImageCaches();
581
0
  return NS_OK;
582
0
}
583
584
void
585
TreeBoxObject::RemoveImageCacheEntry(int32_t aRowIndex, nsTreeColumn& aCol, ErrorResult& aRv)
586
0
{
587
0
  if (NS_WARN_IF(aRowIndex < 0)) {
588
0
    aRv.Throw(NS_ERROR_INVALID_ARG);
589
0
    return;
590
0
  }
591
0
  nsTreeBodyFrame* body = GetTreeBodyFrame();
592
0
  if (body) {
593
0
    body->RemoveImageCacheEntry(aRowIndex, &aCol);
594
0
  }
595
0
}
596
597
void
598
TreeBoxObject::ClearCachedValues()
599
0
{
600
0
  mTreeBody = nullptr;
601
0
}
602
603
JSObject*
604
TreeBoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
605
0
{
606
0
  return TreeBoxObject_Binding::Wrap(aCx, this, aGivenProto);
607
0
}
608
609
} // namespace dom
610
} // namespace mozilla