forked from rnewman/services-central-old
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nsDisplayList.h
2096 lines (1916 loc) · 81.4 KB
/
nsDisplayList.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=2 sw=2 et tw=78:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Novell code.
*
* The Initial Developer of the Original Code is Novell Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* robert@ocallahan.org
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK *****
*/
/*
* structures that represent things to be painted (ordered in z-order),
* used during painting and hit testing
*/
#ifndef NSDISPLAYLIST_H_
#define NSDISPLAYLIST_H_
#include "nsCOMPtr.h"
#include "nsIFrame.h"
#include "nsPoint.h"
#include "nsRect.h"
#include "nsISelection.h"
#include "nsCaret.h"
#include "plarena.h"
#include "Layers.h"
#include "nsRegion.h"
#include "FrameLayerBuilder.h"
#include "nsThemeConstants.h"
#include <stdlib.h>
class nsIPresShell;
class nsIContent;
class nsIRenderingContext;
class nsIDeviceContext;
class nsDisplayTableItem;
class nsDisplayItem;
/*
* An nsIFrame can have many different visual parts. For example an image frame
* can have a background, border, and outline, the image itself, and a
* translucent selection overlay. In general these parts can be drawn at
* discontiguous z-levels; see CSS2.1 appendix E:
* http://www.w3.org/TR/CSS21/zindex.html
*
* We construct a display list for a frame tree that contains one item
* for each visual part. The display list is itself a tree since some items
* are containers for other items; however, its structure does not match
* the structure of its source frame tree. The display list items are sorted
* by z-order. A display list can be used to paint the frames, to determine
* which frame is the target of a mouse event, and to determine what areas
* need to be repainted when scrolling. The display lists built for each task
* may be different for efficiency; in particular some frames need special
* display list items only for event handling, and do not create these items
* when the display list will be used for painting (the common case). For
* example, when painting we avoid creating nsDisplayBackground items for
* frames that don't display a visible background, but for event handling
* we need those backgrounds because they are not transparent to events.
*
* We could avoid constructing an explicit display list by traversing the
* frame tree multiple times in clever ways. However, reifying the display list
* reduces code complexity and reduces the number of times each frame must be
* traversed to one, which seems to be good for performance. It also means
* we can share code for painting, event handling and scroll analysis.
*
* Display lists are short-lived; content and frame trees cannot change
* between a display list being created and destroyed. Display lists should
* not be created during reflow because the frame tree may be in an
* inconsistent state (e.g., a frame's stored overflow-area may not include
* the bounds of all its children). However, it should be fine to create
* a display list while a reflow is pending, before it starts.
*
* A display list covers the "extended" frame tree; the display list for a frame
* tree containing FRAME/IFRAME elements can include frames from the subdocuments.
*/
// All types are defined in nsDisplayItemTypes.h
#ifdef NS_DEBUG
#define NS_DISPLAY_DECL_NAME(n, e) \
virtual const char* Name() { return n; } \
virtual Type GetType() { return e; }
#else
#define NS_DISPLAY_DECL_NAME(n, e) \
virtual Type GetType() { return e; }
#endif
/**
* This manages a display list and is passed as a parameter to
* nsIFrame::BuildDisplayList.
* It contains the parameters that don't change from frame to frame and manages
* the display list memory using a PLArena. It also establishes the reference
* coordinate system for all display list items. Some of the parameters are
* available from the prescontext/presshell, but we copy them into the builder
* for faster/more convenient access.
*/
class nsDisplayListBuilder {
public:
typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
typedef mozilla::FrameLayerBuilder FrameLayerBuilder;
typedef nsIWidget::ThemeGeometry ThemeGeometry;
/**
* @param aReferenceFrame the frame at the root of the subtree; its origin
* is the origin of the reference coordinate system for this display list
* @param aIsForEvents PR_TRUE if we're creating this list in order to
* determine which frame is under the mouse position
* @param aBuildCaret whether or not we should include the caret in any
* display lists that we make.
*/
enum Mode {
PAINTING,
EVENT_DELIVERY,
PLUGIN_GEOMETRY,
OTHER
};
nsDisplayListBuilder(nsIFrame* aReferenceFrame, Mode aMode, PRBool aBuildCaret);
~nsDisplayListBuilder();
/**
* @return PR_TRUE if the display is being built in order to determine which
* frame is under the mouse position.
*/
PRBool IsForEventDelivery() { return mMode == EVENT_DELIVERY; }
/**
* @return PR_TRUE if the display list is being built to compute geometry
* for plugins.
*/
PRBool IsForPluginGeometry() { return mMode == PLUGIN_GEOMETRY; }
/**
* @return PR_TRUE if the display list is being built for painting.
*/
PRBool IsForPainting() { return mMode == PAINTING; }
/**
* @return PR_TRUE if "painting is suppressed" during page load and we
* should paint only the background of the document.
*/
PRBool IsBackgroundOnly() {
NS_ASSERTION(mPresShellStates.Length() > 0,
"don't call this if we're not in a presshell");
return CurrentPresShellState()->mIsBackgroundOnly;
}
/**
* @return PR_TRUE if the currently active BuildDisplayList call is being
* applied to a frame at the root of a pseudo stacking context. A pseudo
* stacking context is either a real stacking context or basically what
* CSS2.1 appendix E refers to with "treat the element as if it created
* a new stacking context
*/
PRBool IsAtRootOfPseudoStackingContext() { return mIsAtRootOfPseudoStackingContext; }
/**
* @return the selection that painting should be restricted to (or nsnull
* in the normal unrestricted case)
*/
nsISelection* GetBoundingSelection() { return mBoundingSelection; }
/**
* @return the root of the display list's frame (sub)tree, whose origin
* establishes the coordinate system for the display list
*/
nsIFrame* ReferenceFrame() { return mReferenceFrame; }
/**
* @return a point pt such that adding pt to a coordinate relative to aFrame
* makes it relative to ReferenceFrame(), i.e., returns
* aFrame->GetOffsetToCrossDoc(ReferenceFrame()). The returned point is in
* the appunits of aFrame. It may be optimized to be faster than
* aFrame->GetOffsetToCrossDoc(ReferenceFrame()) (but currently isn't).
*/
nsPoint ToReferenceFrame(const nsIFrame* aFrame) {
return aFrame->GetOffsetToCrossDoc(ReferenceFrame());
}
/**
* When building the display list, the scrollframe aFrame will be "ignored"
* for the purposes of clipping, and its scrollbars will be hidden. We use
* this to allow RenderOffscreen to render a whole document without beign
* clipped by the viewport or drawing the viewport scrollbars.
*/
void SetIgnoreScrollFrame(nsIFrame* aFrame) { mIgnoreScrollFrame = aFrame; }
/**
* Get the scrollframe to ignore, if any.
*/
nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; }
/**
* Calling this setter makes us include all out-of-flow descendant
* frames in the display list, wherever they may be positioned (even
* outside the dirty rects).
*/
void SetIncludeAllOutOfFlows() { mIncludeAllOutOfFlows = PR_TRUE; }
PRBool GetIncludeAllOutOfFlows() const { return mIncludeAllOutOfFlows; }
/**
* Calling this setter makes us exclude all leaf frames that does
* not have the NS_FRAME_SELECTED_CONTENT bit.
*/
void SetSelectedFramesOnly() { mSelectedFramesOnly = PR_TRUE; }
PRBool GetSelectedFramesOnly() { return mSelectedFramesOnly; }
/**
* Calling this setter makes us compute accurate visible regions at the cost
* of performance if regions get very complex.
*/
void SetAccurateVisibleRegions() { mAccurateVisibleRegions = PR_TRUE; }
PRBool GetAccurateVisibleRegions() { return mAccurateVisibleRegions; }
/**
* Allows callers to selectively override the regular paint suppression checks,
* so that methods like GetFrameForPoint work when painting is suppressed.
*/
void IgnorePaintSuppression() { mIgnoreSuppression = PR_TRUE; }
/**
* @return Returns if this builder will ignore paint suppression.
*/
PRBool IsIgnoringPaintSuppression() { return mIgnoreSuppression; }
/**
* @return Returns if this builder had to ignore painting suppression on some
* document when building the display list.
*/
PRBool GetHadToIgnorePaintSuppression() { return mHadToIgnoreSuppression; }
/**
* Call this if we're doing normal painting to the window.
*/
void SetPaintingToWindow(PRBool aToWindow) { mIsPaintingToWindow = aToWindow; }
PRBool IsPaintingToWindow() const { return mIsPaintingToWindow; }
/**
* Display the caret if needed.
*/
nsresult DisplayCaret(nsIFrame* aFrame, const nsRect& aDirtyRect,
nsDisplayList* aList) {
nsIFrame* frame = GetCaretFrame();
if (aFrame != frame) {
return NS_OK;
}
return frame->DisplayCaret(this, aDirtyRect, aList);
}
/**
* Get the frame that the caret is supposed to draw in.
* If the caret is currently invisible, this will be null.
*/
nsIFrame* GetCaretFrame() {
return CurrentPresShellState()->mCaretFrame;
}
/**
* Get the caret associated with the current presshell.
*/
nsCaret* GetCaret();
/**
* Notify the display list builder that we're entering a presshell.
* aReferenceFrame should be a frame in the new presshell and aDirtyRect
* should be the current dirty rect in aReferenceFrame's coordinate space.
*/
void EnterPresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect);
/**
* Notify the display list builder that we're leaving a presshell.
*/
void LeavePresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect);
/**
* Returns true if we're currently building a display list that's
* directly or indirectly under an nsDisplayTransform or SVG
* foreignObject.
*/
PRBool IsInTransform() { return mInTransform; }
/**
* Indicate whether or not we're directly or indirectly under and
* nsDisplayTransform or SVG foreignObject.
*/
void SetInTransform(PRBool aInTransform) { mInTransform = aInTransform; }
/**
* Returns true if snapping is enabled for the final drawing context.
* The default is true.
*/
PRBool IsSnappingEnabled() { return mSnappingEnabled; }
/**
* Set if snapping is enabled for the final drawing context.
*/
void SetSnappingEnabled(PRBool aSnappingEnabled) { mSnappingEnabled = aSnappingEnabled; }
/**
* @return PR_TRUE if images have been set to decode synchronously.
*/
PRBool ShouldSyncDecodeImages() { return mSyncDecodeImages; }
/**
* Indicates whether we should synchronously decode images. If true, we decode
* and draw whatever image data has been loaded. If false, we just draw
* whatever has already been decoded.
*/
void SetSyncDecodeImages(PRBool aSyncDecodeImages) {
mSyncDecodeImages = aSyncDecodeImages;
}
/**
* Helper method to generate background painting flags based on the
* information available in the display list builder. Currently only
* accounts for mSyncDecodeImages.
*/
PRUint32 GetBackgroundPaintFlags();
/**
* Subtracts aRegion from *aVisibleRegion. We avoid letting
* aVisibleRegion become overcomplex by simplifying it if necessary ---
* unless mAccurateVisibleRegions is set, in which case we let it
* get arbitrarily complex. If aForceSubtract is true then we subtract
* aRegion even if it makes the visible region more complex.
*/
void SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
const nsRegion& aRegion,
PRBool aForceSubtract = PR_FALSE);
/**
* Mark the frames in aFrames to be displayed if they intersect aDirtyRect
* (which is relative to aDirtyFrame). If the frames have placeholders
* that might not be displayed, we mark the placeholders and their ancestors
* to ensure that display list construction descends into them
* anyway. nsDisplayListBuilder will take care of unmarking them when it is
* destroyed.
*/
void MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
const nsFrameList& aFrames,
const nsRect& aDirtyRect);
/**
* Return the FrameLayerBuilder.
*/
FrameLayerBuilder* LayerBuilder() { return &mLayerBuilder; }
/**
* Get the area of the final transparent region.
*/
const nsRegion* GetFinalTransparentRegion() { return mFinalTransparentRegion; }
/**
* Record the area of the final transparent region after all visibility
* calculations were performed.
*/
void SetFinalTransparentRegion(const nsRegion& aFinalTransparentRegion)
{
mFinalTransparentRegion = &aFinalTransparentRegion;
}
const nsTArray<ThemeGeometry>& GetThemeGeometries() { return mThemeGeometries; }
/**
* Returns true if we need to descend into this frame when building
* the display list, even though it doesn't intersect the dirty
* rect, because it may have out-of-flows that do so.
*/
bool ShouldDescendIntoFrame(nsIFrame* aFrame) const {
return
(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) ||
GetIncludeAllOutOfFlows();
}
/**
* Notifies the builder that a particular themed widget exists
* at the given rectangle within the currently built display list.
* For certain appearance values (currently only
* NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR and NS_THEME_TOOLBAR) this gets
* called during every display list construction, for every themed widget of
* the right type within the display list, except for themed widgets which
* are transformed or have effects applied to them (e.g. CSS opacity or
* filters).
*
* @param aWidgetType the -moz-appearance value for the themed widget
* @param aRect the device-pixel rect relative to the widget's displayRoot
* for the themed widget
*/
void RegisterThemeGeometry(PRUint8 aWidgetType,
const nsIntRect& aRect) {
if (mIsPaintingToWindow && mPresShellStates.Length() == 1) {
ThemeGeometry geometry(aWidgetType, aRect);
mThemeGeometries.AppendElement(geometry);
}
}
/**
* Allocate memory in our arena. It will only be freed when this display list
* builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
* destructors are called as soon as the item is no longer used.
*/
void* Allocate(size_t aSize);
/**
* A helper class to temporarily set the value of
* mIsAtRootOfPseudoStackingContext.
*/
class AutoIsRootSetter;
friend class AutoIsRootSetter;
class AutoIsRootSetter {
public:
AutoIsRootSetter(nsDisplayListBuilder* aBuilder, PRBool aIsRoot)
: mBuilder(aBuilder), mOldValue(aBuilder->mIsAtRootOfPseudoStackingContext) {
aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
}
~AutoIsRootSetter() {
mBuilder->mIsAtRootOfPseudoStackingContext = mOldValue;
}
private:
nsDisplayListBuilder* mBuilder;
PRPackedBool mOldValue;
};
/**
* A helper class to temporarily set the value of mInTransform.
*/
class AutoInTransformSetter;
friend class AutoInTransformSetter;
class AutoInTransformSetter {
public:
AutoInTransformSetter(nsDisplayListBuilder* aBuilder, PRBool aInTransform)
: mBuilder(aBuilder), mOldValue(aBuilder->mInTransform) {
aBuilder->mInTransform = aInTransform;
}
~AutoInTransformSetter() {
mBuilder->mInTransform = mOldValue;
}
private:
nsDisplayListBuilder* mBuilder;
PRPackedBool mOldValue;
};
// Helpers for tables
nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; }
void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; }
NS_DECLARE_FRAME_PROPERTY(OutOfFlowDirtyRectProperty, nsIFrame::DestroyRect)
nsPresContext* CurrentPresContext() {
return CurrentPresShellState()->mPresShell->GetPresContext();
}
private:
struct PresShellState {
nsIPresShell* mPresShell;
nsIFrame* mCaretFrame;
PRUint32 mFirstFrameMarkedForDisplay;
PRPackedBool mIsBackgroundOnly;
};
PresShellState* CurrentPresShellState() {
NS_ASSERTION(mPresShellStates.Length() > 0,
"Someone forgot to enter a presshell");
return &mPresShellStates[mPresShellStates.Length() - 1];
}
FrameLayerBuilder mLayerBuilder;
nsIFrame* mReferenceFrame;
nsIFrame* mIgnoreScrollFrame;
PLArenaPool mPool;
nsCOMPtr<nsISelection> mBoundingSelection;
nsAutoTArray<PresShellState,8> mPresShellStates;
nsAutoTArray<nsIFrame*,100> mFramesMarkedForDisplay;
nsAutoTArray<ThemeGeometry,2> mThemeGeometries;
nsDisplayTableItem* mCurrentTableItem;
const nsRegion* mFinalTransparentRegion;
Mode mMode;
PRPackedBool mBuildCaret;
PRPackedBool mIgnoreSuppression;
PRPackedBool mHadToIgnoreSuppression;
PRPackedBool mIsAtRootOfPseudoStackingContext;
PRPackedBool mIncludeAllOutOfFlows;
PRPackedBool mSelectedFramesOnly;
PRPackedBool mAccurateVisibleRegions;
// True when we're building a display list that's directly or indirectly
// under an nsDisplayTransform
PRPackedBool mInTransform;
PRPackedBool mSyncDecodeImages;
PRPackedBool mIsPaintingToWindow;
PRPackedBool mSnappingEnabled;
};
class nsDisplayItem;
class nsDisplayList;
/**
* nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
* nsDisplayItemLink holds the link. The lists are linked from lowest to
* highest in z-order.
*/
class nsDisplayItemLink {
// This is never instantiated directly, so no need to count constructors and
// destructors.
protected:
nsDisplayItemLink() : mAbove(nsnull) {}
nsDisplayItem* mAbove;
friend class nsDisplayList;
};
/**
* This is the unit of rendering and event testing. Each instance of this
* class represents an entity that can be drawn on the screen, e.g., a
* frame's CSS background, or a frame's text string.
*
* nsDisplayListItems can be containers --- i.e., they can perform hit testing
* and painting by recursively traversing a list of child items.
*
* These are arena-allocated during display list construction. A typical
* subclass would just have a frame pointer, so its object would be just three
* pointers (vtable, next-item, frame).
*
* Display items belong to a list at all times (except temporarily as they
* move from one list to another).
*/
class nsDisplayItem : public nsDisplayItemLink {
public:
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::LayerState LayerState;
// This is never instantiated directly (it has pure virtual methods), so no
// need to count constructors and destructors.
nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) :
mFrame(aFrame) {
if (aFrame) {
mToReferenceFrame = aBuilder->ToReferenceFrame(aFrame);
}
}
virtual ~nsDisplayItem() {}
void* operator new(size_t aSize,
nsDisplayListBuilder* aBuilder) CPP_THROW_NEW {
return aBuilder->Allocate(aSize);
}
// Contains all the type integers for each display list item type
#include "nsDisplayItemTypes.h"
struct HitTestState {
typedef nsTArray<ViewID> ShadowArray;
HitTestState(ShadowArray* aShadows = NULL)
: mShadows(aShadows) {
}
~HitTestState() {
NS_ASSERTION(mItemBuffer.Length() == 0,
"mItemBuffer should have been cleared");
}
nsAutoTArray<nsDisplayItem*, 100> mItemBuffer;
// It is sometimes useful to hit test for frames that are not in this
// process. Display items may append IDs into this array if it is
// non-null.
ShadowArray* mShadows;
};
/**
* Some consecutive items should be rendered together as a unit, e.g.,
* outlines for the same element. For this, we need a way for items to
* identify their type. We use the type for other purposes too.
*/
virtual Type GetType() = 0;
/**
* If this returns a non-zero value, then pairing this with the
* GetUnderlyingFrame() pointer gives a key that uniquely identifies
* this display item in the display item tree.
* This will only return a zero value for items which wrap display lists
* and do not create a CSS stacking context, therefore requiring
* display items to be individually wrapped --- currently nsDisplayClip
* and nsDisplayClipRoundedRect only.
*/
virtual PRUint32 GetPerFrameKey() { return PRUint32(GetType()); }
/**
* This is called after we've constructed a display list for event handling.
* When this is called, we've already ensured that aRect intersects the
* item's bounds.
*
* @param aState must point to a HitTestState. If you don't have one,
* just create one with the default constructor and pass it in.
* @param aOutFrames each item appends the frame(s) in this display item that
* the rect is considered over (if any) to aOutFrames.
*/
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {}
/**
* @return the frame that this display item is based on. This is used to sort
* items by z-index and content order and for some other uses. For some items
* that wrap item lists, this could return nsnull because there is no single
* underlying frame; for leaf items it will never return nsnull.
*/
inline nsIFrame* GetUnderlyingFrame() { return mFrame; }
/**
* The default bounds is the frame border rect.
* @return a rectangle relative to aBuilder->ReferenceFrame() that
* contains the area drawn by this display item
*/
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
}
/**
* @return a region of the item that is opaque --- every pixel painted
* with an opaque color.
*/
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull)
{
if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE;
}
return nsRegion();
}
/**
* If this returns true, then aColor is set to the uniform color
* @return PR_TRUE if the item is guaranteed to paint every pixel in its
* bounds with the same (possibly translucent) color
*/
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { return PR_FALSE; }
/**
* @return PR_FALSE if the painting performed by the item is invariant
* when the item's underlying frame is moved relative to aFrame.
* In other words, if you render the item at locations P and P', the rendering
* only differs by the translation.
* It return PR_TRUE for all wrapped lists.
*/
virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame)
{ return PR_FALSE; }
/**
* @return PR_TRUE if the contents of this item are rendered fixed relative
* to the nearest viewport *and* they cover the viewport's scrollport.
* Only return true if the contents actually vary when scrolling in the viewport.
*/
virtual PRBool IsFixedAndCoveringViewport(nsDisplayListBuilder* aBuilder)
{ return PR_FALSE; }
/**
* @return LAYER_NONE if BuildLayer will return null. In this case
* there is no layer for the item, and Paint should be called instead
* to paint the content using Thebes.
* Return LAYER_INACTIVE if there is a layer --- BuildLayer will
* not return null (unless there's an error) --- but the layer contents
* are not changing frequently. In this case it makes sense to composite
* the layer into a ThebesLayer with other content, so we don't have to
* recomposite it every time we paint.
* Note: GetLayerState is only allowed to return LAYER_INACTIVE if all
* descendant display items returned LAYER_INACTIVE or LAYER_NONE. Also,
* all descendant display item frames must have an active scrolled root
* that's either the same as this item's frame's active scrolled root, or
* a descendant of this item's frame. This ensures that the entire
* set of display items can be collapsed onto a single ThebesLayer.
* Return LAYER_ACTIVE if the layer is active, that is, its contents are
* changing frequently. In this case it makes sense to keep the layer
* as a separate buffer in VRAM and composite it into the destination
* every time we paint.
*/
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
{ return mozilla::LAYER_NONE; }
/**
* Actually paint this item to some rendering context.
* Content outside mVisibleRect need not be painted.
* aCtx must be set up as for nsDisplayList::Paint.
*/
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx) {}
/**
* Get the layer drawn by this display item. Call this only if
* GetLayerState() returns something other than LAYER_NONE.
* If GetLayerState returned LAYER_NONE then Paint will be called
* instead.
* This is called while aManager is in the construction phase.
*
* The caller (nsDisplayList) is responsible for setting the visible
* region of the layer.
*/
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager)
{ return nsnull; }
/**
* On entry, aVisibleRegion contains the region (relative to ReferenceFrame())
* which may be visible. If the display item opaquely covers an area, it
* can remove that area from aVisibleRegion before returning.
* nsDisplayList::ComputeVisibility automatically subtracts the region
* returned by GetOpaqueRegion, and automatically removes items whose bounds
* do not intersect the visible area, so implementations of
* nsDisplayItem::ComputeVisibility do not need to do these things.
* nsDisplayList::ComputeVisibility will already have set mVisibleRect on
* this item to the intersection of *aVisibleRegion and this item's bounds.
* We rely on that, so this should only be called by
* nsDisplayList::ComputeVisibility or nsDisplayItem::RecomputeVisibility.
* aAllowVisibleRegionExpansion is a rect where we are allowed to
* expand the visible region and is only used for making sure the
* background behind a plugin is visible.
*
* @return PR_TRUE if the item is visible, PR_FALSE if no part of the item
* is visible. aContainsRootContentDocBG is set to true if this item contains
* the background for the root content document.
*/
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion,
PRBool& aContainsRootContentDocBG)
{ return !mVisibleRect.IsEmpty(); }
/**
* Try to merge with the other item (which is below us in the display
* list). This gets used by nsDisplayClip to coalesce clipping operations
* (optimization), by nsDisplayOpacity to merge rendering for the same
* content element into a single opacity group (correctness), and will be
* used by nsDisplayOutline to merge multiple outlines for the same element
* (also for correctness).
* @return PR_TRUE if the merge was successful and the other item should be deleted
*/
virtual PRBool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
return PR_FALSE;
}
/**
* If this is a leaf item we return null, otherwise we return the wrapped
* list.
*/
virtual nsDisplayList* GetList() { return nsnull; }
/**
* Returns the visible rect. Should only be called after ComputeVisibility
* has happened.
*/
const nsRect& GetVisibleRect() { return mVisibleRect; }
#ifdef NS_DEBUG
/**
* For debugging and stuff
*/
virtual const char* Name() = 0;
#endif
nsDisplayItem* GetAbove() { return mAbove; }
/**
* Like ComputeVisibility, but does the work that nsDisplayList
* does per-item:
* -- Intersects GetBounds with aVisibleRegion and puts the result
* in mVisibleRect
* -- Subtracts bounds from aVisibleRegion if the item is opaque
*/
PRBool RecomputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion);
/**
* Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame())
*/
const nsPoint& ToReferenceFrame() {
NS_ASSERTION(mFrame, "No frame?");
return mToReferenceFrame;
}
/**
* Checks if this display item (or any children) contains content that might
* be rendered with component alpha (e.g. subpixel antialiasing). Returns the
* bounds of the area that needs component alpha, or an empty rect if nothing
* in the item does.
*/
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) { return nsRect(); }
/**
* Disable usage of component alpha. Currently only relevant for items that have text.
*/
virtual void DisableComponentAlpha() {}
protected:
friend class nsDisplayList;
nsDisplayItem() {
mAbove = nsnull;
}
nsIFrame* mFrame;
// Result of ToReferenceFrame(mFrame), if mFrame is non-null
nsPoint mToReferenceFrame;
// This is the rectangle that needs to be painted.
// nsDisplayList::ComputeVisibility sets this to the visible region
// of the item by intersecting the current visible region with the bounds
// of the item. Paint implementations can use this to limit their drawing.
// Guaranteed to be contained in GetBounds().
nsRect mVisibleRect;
};
/**
* Manages a singly-linked list of display list items.
*
* mSentinel is the sentinel list value, the first value in the null-terminated
* linked list of items. mTop is the last item in the list (whose 'above'
* pointer is null). This class has no virtual methods. So list objects are just
* two pointers.
*
* Stepping upward through this list is very fast. Stepping downward is very
* slow so we don't support it. The methods that need to step downward
* (HitTest(), ComputeVisibility()) internally build a temporary array of all
* the items while they do the downward traversal, so overall they're still
* linear time. We have optimized for efficient AppendToTop() of both
* items and lists, with minimal codesize. AppendToBottom() is efficient too.
*/
class nsDisplayList {
public:
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::ThebesLayer ThebesLayer;
/**
* Create an empty list.
*/
nsDisplayList() :
mIsOpaque(PR_FALSE)
{
mTop = &mSentinel;
mSentinel.mAbove = nsnull;
#ifdef DEBUG
mDidComputeVisibility = PR_FALSE;
#endif
}
~nsDisplayList() {
if (mSentinel.mAbove) {
NS_WARNING("Nonempty list left over?");
}
DeleteAll();
}
/**
* Append an item to the top of the list. The item must not currently
* be in a list and cannot be null.
*/
void AppendToTop(nsDisplayItem* aItem) {
NS_ASSERTION(aItem, "No item to append!");
NS_ASSERTION(!aItem->mAbove, "Already in a list!");
mTop->mAbove = aItem;
mTop = aItem;
}
/**
* Append a new item to the top of the list. If the item is null we return
* NS_ERROR_OUT_OF_MEMORY. The intended usage is AppendNewToTop(new ...);
*/
nsresult AppendNewToTop(nsDisplayItem* aItem) {
if (!aItem)
return NS_ERROR_OUT_OF_MEMORY;
AppendToTop(aItem);
return NS_OK;
}
/**
* Append a new item to the bottom of the list. If the item is null we return
* NS_ERROR_OUT_OF_MEMORY. The intended usage is AppendNewToBottom(new ...);
*/
nsresult AppendNewToBottom(nsDisplayItem* aItem) {
if (!aItem)
return NS_ERROR_OUT_OF_MEMORY;
AppendToBottom(aItem);
return NS_OK;
}
/**
* Append a new item to the bottom of the list. The item must be non-null
* and not already in a list.
*/
void AppendToBottom(nsDisplayItem* aItem) {
NS_ASSERTION(aItem, "No item to append!");
NS_ASSERTION(!aItem->mAbove, "Already in a list!");
aItem->mAbove = mSentinel.mAbove;
mSentinel.mAbove = aItem;
if (mTop == &mSentinel) {
mTop = aItem;
}
}
/**
* Removes all items from aList and appends them to the top of this list
*/
void AppendToTop(nsDisplayList* aList) {
if (aList->mSentinel.mAbove) {
mTop->mAbove = aList->mSentinel.mAbove;
mTop = aList->mTop;
aList->mTop = &aList->mSentinel;
aList->mSentinel.mAbove = nsnull;
}
}
/**
* Removes all items from aList and prepends them to the bottom of this list
*/
void AppendToBottom(nsDisplayList* aList) {
if (aList->mSentinel.mAbove) {
aList->mTop->mAbove = mSentinel.mAbove;
mTop = aList->mTop;
mSentinel.mAbove = aList->mSentinel.mAbove;
aList->mTop = &aList->mSentinel;
aList->mSentinel.mAbove = nsnull;
}
}
/**
* Remove an item from the bottom of the list and return it.
*/
nsDisplayItem* RemoveBottom();
/**
* Remove all items from the list and call their destructors.
*/
void DeleteAll();
/**
* @return the item at the top of the list, or null if the list is empty
*/
nsDisplayItem* GetTop() const {
return mTop != &mSentinel ? static_cast<nsDisplayItem*>(mTop) : nsnull;
}
/**
* @return the item at the bottom of the list, or null if the list is empty
*/
nsDisplayItem* GetBottom() const { return mSentinel.mAbove; }
PRBool IsEmpty() const { return mTop == &mSentinel; }
/**
* This is *linear time*!
* @return the number of items in the list
*/
PRUint32 Count() const;
/**
* Stable sort the list by the z-order of GetUnderlyingFrame() on
* each item. 'auto' is counted as zero. Content order is used as the
* secondary order.
* @param aCommonAncestor a common ancestor of all the content elements
* associated with the display items, for speeding up tree order
* checks, or nsnull if not known; it's only a hint, if it is not an
* ancestor of some elements, then we lose performance but not correctness
*/
void SortByZOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor);
/**
* Stable sort the list by the tree order of the content of
* GetUnderlyingFrame() on each item. z-index is ignored.
* @param aCommonAncestor a common ancestor of all the content elements
* associated with the display items, for speeding up tree order
* checks, or nsnull if not known; it's only a hint, if it is not an
* ancestor of some elements, then we lose performance but not correctness
*/
void SortByContentOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor);
/**
* Generic stable sort. Take care, because some of the items might be nsDisplayLists
* themselves.
* aCmp(item1, item2) should return true if item1 <= item2. We sort the items
* into increasing order.
*/
typedef PRBool (* SortLEQ)(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
void* aClosure);
void Sort(nsDisplayListBuilder* aBuilder, SortLEQ aCmp, void* aClosure);
/**
* Compute visiblity for the items in the list.
* We put this logic here so it can be shared by top-level
* painting and also display items that maintain child lists.
* This is also a good place to put ComputeVisibility-related logic
* that must be applied to every display item. In particular, this
* sets mVisibleRect on each display item.
* This sets mIsOpaque if the entire visible area of this list has
* been removed from aVisibleRegion when we return.
* This does not remove any items from the list, so we can recompute
* visiblity with different regions later (see
* FrameLayerBuilder::DrawThebesLayer).
*
* @param aVisibleRegion the area that is visible, relative to the
* reference frame; on return, this contains the area visible under the list.
* I.e., opaque contents of this list are subtracted from aVisibleRegion.
* @param aListVisibleBounds must be equal to the bounds of the intersection
* of aVisibleRegion and GetBounds() for this list.
* @return true if any item in the list is visible. aContainsRootContentDocBG
* is set to true if the list contains the background for a root content
* document.
*/
PRBool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
const nsRect& aListVisibleBounds,
const nsRect& aAllowVisibleRegionExpansion,