Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/xul/BoxObject.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/BoxObject.h"
8
#include "nsCOMPtr.h"
9
#include "nsIDocument.h"
10
#include "nsIPresShell.h"
11
#include "nsPresContext.h"
12
#include "nsIContent.h"
13
#include "nsContainerFrame.h"
14
#include "nsIDocShell.h"
15
#include "nsReadableUtils.h"
16
#include "nsView.h"
17
#include "nsLayoutUtils.h"
18
#include "nsISupportsPrimitives.h"
19
#include "nsSupportsPrimitives.h"
20
#include "mozilla/dom/Element.h"
21
#include "nsComponentManagerUtils.h"
22
#include "mozilla/dom/BoxObjectBinding.h"
23
24
// Implementation /////////////////////////////////////////////////////////////////
25
26
namespace mozilla {
27
namespace dom {
28
29
// Static member variable initialization
30
31
// Implement our nsISupports methods
32
NS_IMPL_CYCLE_COLLECTION_CLASS(BoxObject)
33
NS_IMPL_CYCLE_COLLECTING_ADDREF(BoxObject)
34
NS_IMPL_CYCLE_COLLECTING_RELEASE(BoxObject)
35
36
// QueryInterface implementation for BoxObject
37
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BoxObject)
38
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
39
0
  NS_INTERFACE_MAP_ENTRY(nsIBoxObject)
40
0
  NS_INTERFACE_MAP_ENTRY(nsPIBoxObject)
41
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
42
0
NS_INTERFACE_MAP_END
43
44
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BoxObject)
45
0
  // XXX jmorton: why aren't we unlinking mPropertyTable?
46
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
47
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
48
49
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BoxObject)
50
0
  if (tmp->mPropertyTable) {
51
0
    for (auto iter = tmp->mPropertyTable->Iter(); !iter.Done(); iter.Next()) {
52
0
      cb.NoteXPCOMChild(iter.UserData());
53
0
    }
54
0
  }
55
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
56
57
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BoxObject)
58
59
// Constructors/Destructors
60
BoxObject::BoxObject()
61
  : mContent(nullptr)
62
0
{
63
0
}
64
65
BoxObject::~BoxObject()
66
0
{
67
0
}
68
69
NS_IMETHODIMP
70
BoxObject::GetElement(Element** aResult)
71
0
{
72
0
  RefPtr<Element> element = mContent;
73
0
  element.forget(aResult);
74
0
  return NS_OK;
75
0
}
76
77
// nsPIBoxObject //////////////////////////////////////////////////////////////////////////
78
79
nsresult
80
BoxObject::Init(Element* aElement)
81
0
{
82
0
  mContent = aElement;
83
0
  return NS_OK;
84
0
}
85
86
void
87
BoxObject::Clear()
88
0
{
89
0
  mPropertyTable = nullptr;
90
0
  mContent = nullptr;
91
0
}
92
93
void
94
BoxObject::ClearCachedValues()
95
0
{
96
0
}
97
98
nsIFrame*
99
BoxObject::GetFrame(bool aFlushLayout)
100
0
{
101
0
  nsIPresShell* shell = GetPresShell(aFlushLayout);
102
0
  if (!shell)
103
0
    return nullptr;
104
0
105
0
  if (!aFlushLayout) {
106
0
    // If we didn't flush layout when getting the presshell, we should at least
107
0
    // flush to make sure our frame model is up to date.
108
0
    // XXXbz should flush on document, no?  Except people call this from
109
0
    // frame code, maybe?
110
0
    shell->FlushPendingNotifications(FlushType::Frames);
111
0
  }
112
0
113
0
  // The flush might have killed mContent.
114
0
  if (!mContent) {
115
0
    return nullptr;
116
0
  }
117
0
118
0
  return mContent->GetPrimaryFrame();
119
0
}
120
121
nsIPresShell*
122
BoxObject::GetPresShell(bool aFlushLayout)
123
0
{
124
0
  if (!mContent) {
125
0
    return nullptr;
126
0
  }
127
0
128
0
  nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
129
0
  if (!doc) {
130
0
    return nullptr;
131
0
  }
132
0
133
0
  if (aFlushLayout) {
134
0
    doc->FlushPendingNotifications(FlushType::Layout);
135
0
  }
136
0
137
0
  return doc->GetShell();
138
0
}
139
140
nsresult
141
BoxObject::GetOffsetRect(nsIntRect& aRect)
142
0
{
143
0
  aRect.SetRect(0, 0, 0, 0);
144
0
145
0
  if (!mContent)
146
0
    return NS_ERROR_NOT_INITIALIZED;
147
0
148
0
  // Get the Frame for our content
149
0
  nsIFrame* frame = GetFrame(true);
150
0
  if (frame) {
151
0
    // Get its origin
152
0
    nsPoint origin = frame->GetPositionIgnoringScrolling();
153
0
154
0
    // Find the frame parent whose content is the document element.
155
0
    Element* docElement = mContent->GetComposedDoc()->GetRootElement();
156
0
    nsIFrame* parent = frame->GetParent();
157
0
    for (;;) {
158
0
      // If we've hit the document element, break here
159
0
      if (parent->GetContent() == docElement) {
160
0
        break;
161
0
      }
162
0
163
0
      nsIFrame* next = parent->GetParent();
164
0
      if (!next) {
165
0
        NS_WARNING("We should have hit the document element...");
166
0
        origin += parent->GetPosition();
167
0
        break;
168
0
      }
169
0
170
0
      // Add the parent's origin to our own to get to the
171
0
      // right coordinate system
172
0
      origin += next->GetPositionOfChildIgnoringScrolling(parent);
173
0
      parent = next;
174
0
    }
175
0
176
0
    // For the origin, add in the border for the frame
177
0
    const nsStyleBorder* border = frame->StyleBorder();
178
0
    origin.x += border->GetComputedBorderWidth(eSideLeft);
179
0
    origin.y += border->GetComputedBorderWidth(eSideTop);
180
0
181
0
    // And subtract out the border for the parent
182
0
    const nsStyleBorder* parentBorder = parent->StyleBorder();
183
0
    origin.x -= parentBorder->GetComputedBorderWidth(eSideLeft);
184
0
    origin.y -= parentBorder->GetComputedBorderWidth(eSideTop);
185
0
186
0
    aRect.x = nsPresContext::AppUnitsToIntCSSPixels(origin.x);
187
0
    aRect.y = nsPresContext::AppUnitsToIntCSSPixels(origin.y);
188
0
189
0
    // Get the union of all rectangles in this and continuation frames.
190
0
    // It doesn't really matter what we use as aRelativeTo here, since
191
0
    // we only care about the size. Using 'parent' might make things
192
0
    // a bit faster by speeding up the internal GetOffsetTo operations.
193
0
    nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, parent);
194
0
    aRect.width = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width);
195
0
    aRect.height = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height);
196
0
  }
197
0
198
0
  return NS_OK;
199
0
}
200
201
nsresult
202
BoxObject::GetScreenPosition(nsIntPoint& aPoint)
203
0
{
204
0
  aPoint.x = aPoint.y = 0;
205
0
206
0
  if (!mContent)
207
0
    return NS_ERROR_NOT_INITIALIZED;
208
0
209
0
  nsIFrame* frame = GetFrame(true);
210
0
  if (frame) {
211
0
    CSSIntRect rect = frame->GetScreenRect();
212
0
    aPoint.x = rect.x;
213
0
    aPoint.y = rect.y;
214
0
  }
215
0
216
0
  return NS_OK;
217
0
}
218
219
NS_IMETHODIMP
220
BoxObject::GetX(int32_t* aResult)
221
0
{
222
0
  nsIntRect rect;
223
0
  GetOffsetRect(rect);
224
0
  *aResult = rect.x;
225
0
  return NS_OK;
226
0
}
227
228
NS_IMETHODIMP
229
BoxObject::GetY(int32_t* aResult)
230
0
{
231
0
  nsIntRect rect;
232
0
  GetOffsetRect(rect);
233
0
  *aResult = rect.y;
234
0
  return NS_OK;
235
0
}
236
237
NS_IMETHODIMP
238
BoxObject::GetWidth(int32_t* aResult)
239
0
{
240
0
  nsIntRect rect;
241
0
  GetOffsetRect(rect);
242
0
  *aResult = rect.width;
243
0
  return NS_OK;
244
0
}
245
246
NS_IMETHODIMP
247
BoxObject::GetHeight(int32_t* aResult)
248
0
{
249
0
  nsIntRect rect;
250
0
  GetOffsetRect(rect);
251
0
  *aResult = rect.height;
252
0
  return NS_OK;
253
0
}
254
255
NS_IMETHODIMP
256
BoxObject::GetScreenX(int32_t *_retval)
257
0
{
258
0
  nsIntPoint position;
259
0
  nsresult rv = GetScreenPosition(position);
260
0
  if (NS_FAILED(rv)) return rv;
261
0
  *_retval = position.x;
262
0
  return NS_OK;
263
0
}
264
265
NS_IMETHODIMP
266
BoxObject::GetScreenY(int32_t *_retval)
267
0
{
268
0
  nsIntPoint position;
269
0
  nsresult rv = GetScreenPosition(position);
270
0
  if (NS_FAILED(rv)) return rv;
271
0
  *_retval = position.y;
272
0
  return NS_OK;
273
0
}
274
275
NS_IMETHODIMP
276
BoxObject::GetPropertyAsSupports(const char16_t* aPropertyName, nsISupports** aResult)
277
0
{
278
0
  NS_ENSURE_ARG(aPropertyName && *aPropertyName);
279
0
  if (!mPropertyTable) {
280
0
    *aResult = nullptr;
281
0
    return NS_OK;
282
0
  }
283
0
  nsDependentString propertyName(aPropertyName);
284
0
  mPropertyTable->Get(propertyName, aResult); // Addref here.
285
0
  return NS_OK;
286
0
}
287
288
NS_IMETHODIMP
289
BoxObject::SetPropertyAsSupports(const char16_t* aPropertyName, nsISupports* aValue)
290
0
{
291
0
  NS_ENSURE_ARG(aPropertyName && *aPropertyName);
292
0
293
0
  if (!mPropertyTable) {
294
0
    mPropertyTable = new nsInterfaceHashtable<nsStringHashKey,nsISupports>(4);
295
0
  }
296
0
297
0
  nsDependentString propertyName(aPropertyName);
298
0
  mPropertyTable->Put(propertyName, aValue);
299
0
  return NS_OK;
300
0
}
301
302
NS_IMETHODIMP
303
BoxObject::GetProperty(const char16_t* aPropertyName, char16_t** aResult)
304
0
{
305
0
  nsCOMPtr<nsISupports> data;
306
0
  nsresult rv = GetPropertyAsSupports(aPropertyName,getter_AddRefs(data));
307
0
  NS_ENSURE_SUCCESS(rv, rv);
308
0
309
0
  if (!data) {
310
0
    *aResult = nullptr;
311
0
    return NS_OK;
312
0
  }
313
0
314
0
  nsCOMPtr<nsISupportsString> supportsStr = do_QueryInterface(data);
315
0
  if (!supportsStr) {
316
0
    return NS_ERROR_FAILURE;
317
0
  }
318
0
319
0
  return supportsStr->ToString(aResult);
320
0
}
321
322
NS_IMETHODIMP
323
BoxObject::SetProperty(const char16_t* aPropertyName, const char16_t* aPropertyValue)
324
0
{
325
0
  NS_ENSURE_ARG(aPropertyName && *aPropertyName);
326
0
327
0
  nsDependentString propertyName(aPropertyName);
328
0
  nsDependentString propertyValue;
329
0
  if (aPropertyValue) {
330
0
    propertyValue.Rebind(aPropertyValue);
331
0
  } else {
332
0
    propertyValue.SetIsVoid(true);
333
0
  }
334
0
335
0
  nsCOMPtr<nsISupportsString> supportsStr(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
336
0
  NS_ENSURE_TRUE(supportsStr, NS_ERROR_OUT_OF_MEMORY);
337
0
  supportsStr->SetData(propertyValue);
338
0
339
0
  return SetPropertyAsSupports(aPropertyName,supportsStr);
340
0
}
341
342
NS_IMETHODIMP
343
BoxObject::RemoveProperty(const char16_t* aPropertyName)
344
0
{
345
0
  NS_ENSURE_ARG(aPropertyName && *aPropertyName);
346
0
347
0
  if (!mPropertyTable) return NS_OK;
348
0
349
0
  nsDependentString propertyName(aPropertyName);
350
0
  mPropertyTable->Remove(propertyName);
351
0
  return NS_OK;
352
0
}
353
354
Element*
355
BoxObject::GetParentBox()
356
0
{
357
0
  nsIFrame* frame = GetFrame(false);
358
0
  if (!frame) {
359
0
    return nullptr;
360
0
  }
361
0
362
0
  nsIFrame* parent = frame->GetParent();
363
0
  if (!parent) {
364
0
    return nullptr;
365
0
  }
366
0
367
0
  nsIContent* parentContent = parent->GetContent();
368
0
  // In theory parent could be viewport, and then parentContent is null.
369
0
  if (parentContent && parentContent->IsElement()) {
370
0
    return parentContent->AsElement();
371
0
  }
372
0
373
0
  return nullptr;
374
0
}
375
376
Element*
377
BoxObject::GetFirstChild()
378
0
{
379
0
  nsIFrame* frame = GetFrame(false);
380
0
  if (!frame) {
381
0
    return nullptr;
382
0
  }
383
0
384
0
  nsIFrame* firstFrame = frame->PrincipalChildList().FirstChild();
385
0
  if (!firstFrame) {
386
0
    return nullptr;
387
0
  }
388
0
389
0
  nsIContent* content = firstFrame->GetContent();
390
0
  if (content->IsElement()) {
391
0
    return content->AsElement();
392
0
  }
393
0
394
0
  return nullptr;
395
0
}
396
397
Element*
398
BoxObject::GetLastChild()
399
0
{
400
0
  nsIFrame* frame = GetFrame(false);
401
0
  if (!frame) {
402
0
    return nullptr;
403
0
  }
404
0
  return GetPreviousSibling(frame, nullptr);
405
0
}
406
407
Element*
408
BoxObject::GetNextSibling()
409
0
{
410
0
  nsIFrame* frame = GetFrame(false);
411
0
  if (!frame) {
412
0
    return nullptr;
413
0
  }
414
0
415
0
  nsIFrame* nextFrame = frame->GetNextSibling();
416
0
  if (!nextFrame) {
417
0
    return nullptr;
418
0
  }
419
0
420
0
  nsIContent* content = nextFrame->GetContent();
421
0
  if (content->IsElement()) {
422
0
    return content->AsElement();
423
0
  }
424
0
425
0
  return nullptr;
426
0
}
427
428
Element*
429
BoxObject::GetPreviousSibling()
430
0
{
431
0
  nsIFrame* frame = GetFrame(false);
432
0
  if (!frame) {
433
0
    return nullptr;
434
0
  }
435
0
  nsIFrame* parentFrame = frame->GetParent();
436
0
  if (!parentFrame) {
437
0
    return nullptr;
438
0
  }
439
0
  return GetPreviousSibling(parentFrame, frame);
440
0
}
441
442
Element*
443
BoxObject::GetPreviousSibling(nsIFrame* aParentFrame, nsIFrame* aFrame)
444
0
{
445
0
  nsIFrame* nextFrame = aParentFrame->PrincipalChildList().FirstChild();
446
0
  nsIFrame* prevFrame = nullptr;
447
0
  while (nextFrame) {
448
0
    if (nextFrame == aFrame)
449
0
      break;
450
0
    prevFrame = nextFrame;
451
0
    nextFrame = nextFrame->GetNextSibling();
452
0
  }
453
0
454
0
  if (!prevFrame) {
455
0
    return nullptr;
456
0
  }
457
0
458
0
  nsIContent* content = prevFrame->GetContent();
459
0
  if (!content->IsElement()) {
460
0
    return nullptr;
461
0
  }
462
0
463
0
  return content->AsElement();
464
0
}
465
466
Element*
467
BoxObject::GetParentObject() const
468
0
{
469
0
  return mContent;
470
0
}
471
472
JSObject*
473
BoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
474
0
{
475
0
  return BoxObject_Binding::Wrap(aCx, this, aGivenProto);
476
0
}
477
478
Element*
479
BoxObject::GetElement() const
480
0
{
481
0
  return mContent;
482
0
}
483
484
int32_t
485
BoxObject::X()
486
0
{
487
0
  int32_t ret = 0;
488
0
  GetX(&ret);
489
0
  return ret;
490
0
}
491
492
int32_t
493
BoxObject::Y()
494
0
{
495
0
  int32_t ret = 0;
496
0
  GetY(&ret);
497
0
  return ret;
498
0
}
499
500
int32_t
501
BoxObject::GetScreenX(ErrorResult& aRv)
502
0
{
503
0
  int32_t ret = 0;
504
0
  aRv = GetScreenX(&ret);
505
0
  return ret;
506
0
}
507
508
int32_t
509
BoxObject::GetScreenY(ErrorResult& aRv)
510
0
{
511
0
  int32_t ret = 0;
512
0
  aRv = GetScreenY(&ret);
513
0
  return ret;
514
0
}
515
516
int32_t
517
BoxObject::Width()
518
0
{
519
0
  int32_t ret = 0;
520
0
  GetWidth(&ret);
521
0
  return ret;
522
0
}
523
524
int32_t
525
BoxObject::Height()
526
0
{
527
0
  int32_t ret = 0;
528
0
  GetHeight(&ret);
529
0
  return ret;
530
0
}
531
532
already_AddRefed<nsISupports>
533
BoxObject::GetPropertyAsSupports(const nsAString& propertyName)
534
0
{
535
0
  nsCOMPtr<nsISupports> ret;
536
0
  GetPropertyAsSupports(PromiseFlatString(propertyName).get(), getter_AddRefs(ret));
537
0
  return ret.forget();
538
0
}
539
540
void
541
BoxObject::SetPropertyAsSupports(const nsAString& propertyName, nsISupports* value)
542
0
{
543
0
  SetPropertyAsSupports(PromiseFlatString(propertyName).get(), value);
544
0
}
545
546
void
547
BoxObject::GetProperty(const nsAString& propertyName, nsString& aRetVal, ErrorResult& aRv)
548
0
{
549
0
  nsCOMPtr<nsISupports> data(GetPropertyAsSupports(propertyName));
550
0
  if (!data) {
551
0
    return;
552
0
  }
553
0
554
0
  nsCOMPtr<nsISupportsString> supportsStr(do_QueryInterface(data));
555
0
  if (!supportsStr) {
556
0
    aRv.Throw(NS_ERROR_FAILURE);
557
0
    return;
558
0
  }
559
0
560
0
  supportsStr->GetData(aRetVal);
561
0
}
562
563
void
564
BoxObject::SetProperty(const nsAString& propertyName, const nsAString& propertyValue)
565
0
{
566
0
  SetProperty(PromiseFlatString(propertyName).get(), PromiseFlatString(propertyValue).get());
567
0
}
568
569
void
570
BoxObject::RemoveProperty(const nsAString& propertyName)
571
0
{
572
0
  RemoveProperty(PromiseFlatString(propertyName).get());
573
0
}
574
575
} // namespace dom
576
} // namespace mozilla