Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
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/. */
7 #ifndef TextOverflow_h_
8 #define TextOverflow_h_
10 #include "nsDisplayList.h"
11 #include "nsTHashtable.h"
12 #include "mozilla/Likely.h"
13 #include <algorithm>
15 class nsIScrollableFrame;
16 class gfxTextRun;
17 class nsLineBox;
19 namespace mozilla {
20 namespace css {
22 /**
23 * A class for rendering CSS3 text-overflow.
24 * Usage:
25 * 1. allocate an object using WillProcessLines
26 * 2. then call ProcessLine for each line you are building display lists for
27 */
28 class TextOverflow {
29 public:
30 /**
31 * Allocate an object for text-overflow processing.
32 * @return nullptr if no processing is necessary. The caller owns the object.
33 */
34 static TextOverflow* WillProcessLines(nsDisplayListBuilder* aBuilder,
35 nsIFrame* aBlockFrame);
36 /**
37 * Analyze the display lists for text overflow and what kind of item is at
38 * the content edges. Add display items for text-overflow markers as needed
39 * and remove or clip items that would overlap a marker.
40 */
41 void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine);
43 /**
44 * Get the resulting text-overflow markers (the list may be empty).
45 * @return a DisplayList containing any text-overflow markers.
46 */
47 nsDisplayList& GetMarkers() { return mMarkerList; }
49 /**
50 * @return true if aBlockFrame needs analysis for text overflow.
51 */
52 static bool CanHaveTextOverflow(nsDisplayListBuilder* aBuilder,
53 nsIFrame* aBlockFrame);
55 typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable;
57 protected:
58 TextOverflow() {}
59 void Init(nsDisplayListBuilder* aBuilder,
60 nsIFrame* aBlockFrame);
62 struct AlignmentEdges {
63 AlignmentEdges() : mAssigned(false) {}
64 void Accumulate(const nsRect& aRect) {
65 if (MOZ_LIKELY(mAssigned)) {
66 x = std::min(x, aRect.X());
67 xmost = std::max(xmost, aRect.XMost());
68 } else {
69 x = aRect.X();
70 xmost = aRect.XMost();
71 mAssigned = true;
72 }
73 }
74 nscoord Width() { return xmost - x; }
75 nscoord x;
76 nscoord xmost;
77 bool mAssigned;
78 };
80 struct InnerClipEdges {
81 InnerClipEdges() : mAssignedLeft(false), mAssignedRight(false) {}
82 void AccumulateLeft(const nsRect& aRect) {
83 if (MOZ_LIKELY(mAssignedLeft)) {
84 mLeft = std::max(mLeft, aRect.X());
85 } else {
86 mLeft = aRect.X();
87 mAssignedLeft = true;
88 }
89 }
90 void AccumulateRight(const nsRect& aRect) {
91 if (MOZ_LIKELY(mAssignedRight)) {
92 mRight = std::min(mRight, aRect.XMost());
93 } else {
94 mRight = aRect.XMost();
95 mAssignedRight = true;
96 }
97 }
98 nscoord mLeft;
99 nscoord mRight;
100 bool mAssignedLeft;
101 bool mAssignedRight;
102 };
104 /**
105 * Examines frames on the line to determine whether we should draw a left
106 * and/or right marker, and if so, which frames should be completely hidden
107 * and the bounds of what will be displayed between the markers.
108 * @param aLine the line we're processing
109 * @param aFramesToHide frames that should have their display items removed
110 * @param aAlignmentEdges the outermost edges of all text and atomic
111 * inline-level frames that are inside the area between the markers
112 */
113 void ExamineLineFrames(nsLineBox* aLine,
114 FrameHashtable* aFramesToHide,
115 AlignmentEdges* aAlignmentEdges);
117 /**
118 * LineHasOverflowingText calls this to analyze edges, both the block's
119 * content edges and the hypothetical marker edges aligned at the block edges.
120 * @param aFrame the descendant frame of mBlock that we're analyzing
121 * @param aContentArea the block's content area
122 * @param aInsideMarkersArea the rectangle between the markers
123 * @param aFramesToHide frames that should have their display items removed
124 * @param aAlignmentEdges the outermost edges of all text and atomic
125 * inline-level frames that are inside the area between the markers
126 * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
127 * inline-level frame is visible between the marker edges
128 * @param aClippedMarkerEdges the innermost edges of all text and atomic
129 * inline-level frames that are clipped by the current marker width
130 */
131 void ExamineFrameSubtree(nsIFrame* aFrame,
132 const nsRect& aContentArea,
133 const nsRect& aInsideMarkersArea,
134 FrameHashtable* aFramesToHide,
135 AlignmentEdges* aAlignmentEdges,
136 bool* aFoundVisibleTextOrAtomic,
137 InnerClipEdges* aClippedMarkerEdges);
139 /**
140 * ExamineFrameSubtree calls this to analyze a frame against the hypothetical
141 * marker edges (aInsideMarkersArea) for text frames and atomic inline-level
142 * elements. A text frame adds its extent inside aInsideMarkersArea where
143 * grapheme clusters are fully visible. An atomic adds its border box if
144 * it's fully inside aInsideMarkersArea, otherwise the frame is added to
145 * aFramesToHide.
146 * @param aFrame the descendant frame of mBlock that we're analyzing
147 * @param aFrameType aFrame's frame type
148 * @param aInsideMarkersArea the rectangle between the markers
149 * @param aFramesToHide frames that should have their display items removed
150 * @param aAlignmentEdges the outermost edges of all text and atomic
151 * inline-level frames that are inside the area between the markers
152 * inside aInsideMarkersArea
153 * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
154 * inline-level frame is visible between the marker edges
155 * @param aClippedMarkerEdges the innermost edges of all text and atomic
156 * inline-level frames that are clipped by the current marker width
157 */
158 void AnalyzeMarkerEdges(nsIFrame* aFrame,
159 const nsIAtom* aFrameType,
160 const nsRect& aInsideMarkersArea,
161 FrameHashtable* aFramesToHide,
162 AlignmentEdges* aAlignmentEdges,
163 bool* aFoundVisibleTextOrAtomic,
164 InnerClipEdges* aClippedMarkerEdges);
166 /**
167 * Clip or remove items given the final marker edges. ("clip" here just means
168 * assigning mLeftEdge/mRightEdge for any nsCharClipDisplayItem that needs it,
169 * see nsDisplayList.h for a description of that item).
170 * @param aFramesToHide remove display items for these frames
171 * @param aInsideMarkersArea is the area inside the markers
172 */
173 void PruneDisplayListContents(nsDisplayList* aList,
174 const FrameHashtable& aFramesToHide,
175 const nsRect& aInsideMarkersArea);
177 /**
178 * ProcessLine calls this to create display items for the markers and insert
179 * them into mMarkerList.
180 * @param aLine the line we're processing
181 * @param aCreateLeft if true, create a marker on the left side
182 * @param aCreateRight if true, create a marker on the right side
183 * @param aInsideMarkersArea is the area inside the markers
184 */
185 void CreateMarkers(const nsLineBox* aLine,
186 bool aCreateLeft,
187 bool aCreateRight,
188 const nsRect& aInsideMarkersArea);
190 nsRect mContentArea;
191 nsDisplayListBuilder* mBuilder;
192 nsIFrame* mBlock;
193 nsIScrollableFrame* mScrollableFrame;
194 nsDisplayList mMarkerList;
195 bool mBlockIsRTL;
196 bool mCanHaveHorizontalScrollbar;
197 bool mAdjustForPixelSnapping;
199 class Marker {
200 public:
201 void Init(const nsStyleTextOverflowSide& aStyle) {
202 mInitialized = false;
203 mWidth = 0;
204 mStyle = &aStyle;
205 }
207 /**
208 * Setup the marker string and calculate its size, if not done already.
209 */
210 void SetupString(nsIFrame* aFrame);
212 bool IsNeeded() const {
213 return mHasOverflow;
214 }
215 void Reset() {
216 mHasOverflow = false;
217 }
219 // The current width of the marker, the range is [0 .. mIntrinsicWidth].
220 nscoord mWidth;
221 // The intrinsic width of the marker.
222 nscoord mIntrinsicWidth;
223 // The style for this side.
224 const nsStyleTextOverflowSide* mStyle;
225 // True if there is visible overflowing inline content on this side.
226 bool mHasOverflow;
227 // True if mMarkerString and mWidth have been setup from style.
228 bool mInitialized;
229 // True if the style is text-overflow:clip on this side and the marker
230 // won't cause the line to become empty.
231 bool mActive;
232 };
234 Marker mLeft; // the horizontal left marker
235 Marker mRight; // the horizontal right marker
236 };
238 } // namespace css
239 } // namespace mozilla
241 #endif /* !defined(TextOverflow_h_) */