Line data Source code
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/. */
6 :
7 : #ifndef TextOverflow_h_
8 : #define TextOverflow_h_
9 :
10 : #include "nsDisplayList.h"
11 : #include "nsTHashtable.h"
12 : #include "mozilla/Likely.h"
13 : #include "mozilla/WritingModes.h"
14 : #include <algorithm>
15 :
16 : class nsIScrollableFrame;
17 : class nsLineBox;
18 :
19 : namespace mozilla {
20 : namespace css {
21 :
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 0 : 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);
42 :
43 : /**
44 : * Get the resulting text-overflow markers (the list may be empty).
45 : * @return a DisplayList containing any text-overflow markers.
46 : */
47 0 : nsDisplayList& GetMarkers() { return mMarkerList; }
48 :
49 : /**
50 : * @return true if aBlockFrmae has text-overflow:clip on both sides.
51 : */
52 : static bool HasClippedOverflow(nsIFrame* aBlockFrame);
53 : /**
54 : * @return true if aBlockFrame needs analysis for text overflow.
55 : */
56 : static bool CanHaveTextOverflow(nsIFrame* aBlockFrame);
57 :
58 : typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable;
59 :
60 : protected:
61 : TextOverflow(nsDisplayListBuilder* aBuilder,
62 : nsIFrame* aBlockFrame);
63 :
64 : typedef mozilla::WritingMode WritingMode;
65 : typedef mozilla::LogicalRect LogicalRect;
66 :
67 : struct AlignmentEdges {
68 0 : AlignmentEdges() : mAssigned(false) {}
69 0 : void Accumulate(WritingMode aWM, const LogicalRect& aRect)
70 : {
71 0 : if (MOZ_LIKELY(mAssigned)) {
72 0 : mIStart = std::min(mIStart, aRect.IStart(aWM));
73 0 : mIEnd = std::max(mIEnd, aRect.IEnd(aWM));
74 : } else {
75 0 : mIStart = aRect.IStart(aWM);
76 0 : mIEnd = aRect.IEnd(aWM);
77 0 : mAssigned = true;
78 : }
79 0 : }
80 0 : nscoord ISize() { return mIEnd - mIStart; }
81 : nscoord mIStart;
82 : nscoord mIEnd;
83 : bool mAssigned;
84 : };
85 :
86 : struct InnerClipEdges {
87 0 : InnerClipEdges() : mAssignedIStart(false), mAssignedIEnd(false) {}
88 0 : void AccumulateIStart(WritingMode aWM, const LogicalRect& aRect)
89 : {
90 0 : if (MOZ_LIKELY(mAssignedIStart)) {
91 0 : mIStart = std::max(mIStart, aRect.IStart(aWM));
92 : } else {
93 0 : mIStart = aRect.IStart(aWM);
94 0 : mAssignedIStart = true;
95 : }
96 0 : }
97 0 : void AccumulateIEnd(WritingMode aWM, const LogicalRect& aRect)
98 : {
99 0 : if (MOZ_LIKELY(mAssignedIEnd)) {
100 0 : mIEnd = std::min(mIEnd, aRect.IEnd(aWM));
101 : } else {
102 0 : mIEnd = aRect.IEnd(aWM);
103 0 : mAssignedIEnd = true;
104 : }
105 0 : }
106 : nscoord mIStart;
107 : nscoord mIEnd;
108 : bool mAssignedIStart;
109 : bool mAssignedIEnd;
110 : };
111 :
112 : LogicalRect
113 0 : GetLogicalScrollableOverflowRectRelativeToBlock(nsIFrame* aFrame) const
114 : {
115 : return LogicalRect(mBlockWM,
116 0 : aFrame->GetScrollableOverflowRect() +
117 0 : aFrame->GetOffsetTo(mBlock),
118 0 : mBlockSize);
119 : }
120 :
121 : /**
122 : * Examines frames on the line to determine whether we should draw a left
123 : * and/or right marker, and if so, which frames should be completely hidden
124 : * and the bounds of what will be displayed between the markers.
125 : * @param aLine the line we're processing
126 : * @param aFramesToHide frames that should have their display items removed
127 : * @param aAlignmentEdges the outermost edges of all text and atomic
128 : * inline-level frames that are inside the area between the markers
129 : * @return the area inside which we should add any markers;
130 : * this is the block's content area narrowed by any floats on this line.
131 : */
132 : LogicalRect ExamineLineFrames(nsLineBox* aLine,
133 : FrameHashtable* aFramesToHide,
134 : AlignmentEdges* aAlignmentEdges);
135 :
136 : /**
137 : * LineHasOverflowingText calls this to analyze edges, both the block's
138 : * content edges and the hypothetical marker edges aligned at the block edges.
139 : * @param aFrame the descendant frame of mBlock that we're analyzing
140 : * @param aContentArea the block's content area
141 : * @param aInsideMarkersArea the rectangle between the markers
142 : * @param aFramesToHide frames that should have their display items removed
143 : * @param aAlignmentEdges the outermost edges of all text and atomic
144 : * inline-level frames that are inside the area between the markers
145 : * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
146 : * inline-level frame is visible between the marker edges
147 : * @param aClippedMarkerEdges the innermost edges of all text and atomic
148 : * inline-level frames that are clipped by the current marker width
149 : */
150 : void ExamineFrameSubtree(nsIFrame* aFrame,
151 : const LogicalRect& aContentArea,
152 : const LogicalRect& aInsideMarkersArea,
153 : FrameHashtable* aFramesToHide,
154 : AlignmentEdges* aAlignmentEdges,
155 : bool* aFoundVisibleTextOrAtomic,
156 : InnerClipEdges* aClippedMarkerEdges);
157 :
158 : /**
159 : * ExamineFrameSubtree calls this to analyze a frame against the hypothetical
160 : * marker edges (aInsideMarkersArea) for text frames and atomic inline-level
161 : * elements. A text frame adds its extent inside aInsideMarkersArea where
162 : * grapheme clusters are fully visible. An atomic adds its border box if
163 : * it's fully inside aInsideMarkersArea, otherwise the frame is added to
164 : * aFramesToHide.
165 : * @param aFrame the descendant frame of mBlock that we're analyzing
166 : * @param aFrameType aFrame's frame type
167 : * @param aInsideMarkersArea the rectangle between the markers
168 : * @param aFramesToHide frames that should have their display items removed
169 : * @param aAlignmentEdges the outermost edges of all text and atomic
170 : * inline-level frames that are inside the area between the markers
171 : * inside aInsideMarkersArea
172 : * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
173 : * inline-level frame is visible between the marker edges
174 : * @param aClippedMarkerEdges the innermost edges of all text and atomic
175 : * inline-level frames that are clipped by the current marker width
176 : */
177 : void AnalyzeMarkerEdges(nsIFrame* aFrame,
178 : mozilla::LayoutFrameType aFrameType,
179 : const LogicalRect& aInsideMarkersArea,
180 : FrameHashtable* aFramesToHide,
181 : AlignmentEdges* aAlignmentEdges,
182 : bool* aFoundVisibleTextOrAtomic,
183 : InnerClipEdges* aClippedMarkerEdges);
184 :
185 : /**
186 : * Clip or remove items given the final marker edges. ("clip" here just means
187 : * assigning mVisIStartEdge/mVisIEndEdge for any nsCharClipDisplayItem that
188 : * needs it; see nsDisplayList.h for a description of that item).
189 : * @param aFramesToHide remove display items for these frames
190 : * @param aInsideMarkersArea is the area inside the markers
191 : */
192 : void PruneDisplayListContents(nsDisplayList* aList,
193 : const FrameHashtable& aFramesToHide,
194 : const LogicalRect& aInsideMarkersArea);
195 :
196 : /**
197 : * ProcessLine calls this to create display items for the markers and insert
198 : * them into mMarkerList.
199 : * @param aLine the line we're processing
200 : * @param aCreateIStart if true, create a marker on the inline start side
201 : * @param aCreateIEnd if true, create a marker on the inline end side
202 : * @param aInsideMarkersArea is the area inside the markers
203 : * @param aContentArea is the area inside which we should add the markers;
204 : * this is the block's content area narrowed by any floats on this line.
205 : */
206 : void CreateMarkers(const nsLineBox* aLine,
207 : bool aCreateIStart, bool aCreateIEnd,
208 : const LogicalRect& aInsideMarkersArea,
209 : const LogicalRect& aContentArea);
210 :
211 : LogicalRect mContentArea;
212 : nsDisplayListBuilder* mBuilder;
213 : nsIFrame* mBlock;
214 : nsIScrollableFrame* mScrollableFrame;
215 : nsDisplayList mMarkerList;
216 : nsSize mBlockSize;
217 : WritingMode mBlockWM;
218 : bool mCanHaveInlineAxisScrollbar;
219 : bool mAdjustForPixelSnapping;
220 :
221 : class Marker {
222 : public:
223 0 : void Init(const nsStyleTextOverflowSide& aStyle) {
224 0 : mInitialized = false;
225 0 : mISize = 0;
226 0 : mStyle = &aStyle;
227 0 : }
228 :
229 : /**
230 : * Setup the marker string and calculate its size, if not done already.
231 : */
232 : void SetupString(nsIFrame* aFrame);
233 :
234 0 : bool IsNeeded() const {
235 0 : return mHasOverflow;
236 : }
237 0 : void Reset() {
238 0 : mHasOverflow = false;
239 0 : }
240 :
241 : // The current width of the marker, the range is [0 .. mIntrinsicISize].
242 : nscoord mISize;
243 : // The intrinsic width of the marker.
244 : nscoord mIntrinsicISize;
245 : // The style for this side.
246 : const nsStyleTextOverflowSide* mStyle;
247 : // True if there is visible overflowing inline content on this side.
248 : bool mHasOverflow;
249 : // True if mMarkerString and mWidth have been setup from style.
250 : bool mInitialized;
251 : // True if the style is text-overflow:clip on this side and the marker
252 : // won't cause the line to become empty.
253 : bool mActive;
254 : };
255 :
256 : Marker mIStart; // the inline start marker
257 : Marker mIEnd; // the inline end marker
258 : };
259 :
260 : } // namespace css
261 : } // namespace mozilla
262 :
263 : #endif /* !defined(TextOverflow_h_) */
|