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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is an implementation of CSS3 text-overflow.
17 : *
18 : * The Initial Developer of the Original Code is the Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2011
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Mats Palmgren <matspal@gmail.com> (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef TextOverflow_h_
40 : #define TextOverflow_h_
41 :
42 : #include "nsDisplayList.h"
43 : #include "nsLineBox.h"
44 : #include "nsStyleStruct.h"
45 : #include "nsTHashtable.h"
46 : class nsIScrollableFrame;
47 :
48 : namespace mozilla {
49 : namespace css {
50 :
51 : /**
52 : * A class for rendering CSS3 text-overflow.
53 : * Usage:
54 : * 1. allocate an object using WillProcessLines
55 : * 2. then call ProcessLine for each line you are building display lists for
56 : */
57 0 : class TextOverflow {
58 : public:
59 : /**
60 : * Allocate an object for text-overflow processing.
61 : * @return nsnull if no processing is necessary. The caller owns the object.
62 : */
63 : static TextOverflow* WillProcessLines(nsDisplayListBuilder* aBuilder,
64 : const nsDisplayListSet& aLists,
65 : nsIFrame* aBlockFrame);
66 : /**
67 : * Analyze the display lists for text overflow and what kind of item is at
68 : * the content edges. Add display items for text-overflow markers as needed
69 : * and remove or clip items that would overlap a marker.
70 : */
71 : void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine);
72 :
73 : /**
74 : * @return true if aBlockFrame needs analysis for text overflow.
75 : */
76 : static bool CanHaveTextOverflow(nsDisplayListBuilder* aBuilder,
77 : nsIFrame* aBlockFrame);
78 :
79 : typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable;
80 :
81 : protected:
82 0 : TextOverflow() {}
83 : void Init(nsDisplayListBuilder* aBuilder,
84 : const nsDisplayListSet& aLists,
85 : nsIFrame* aBlockFrame);
86 :
87 : struct AlignmentEdges {
88 0 : AlignmentEdges() : mAssigned(false) {}
89 0 : void Accumulate(const nsRect& aRect) {
90 0 : if (NS_LIKELY(mAssigned)) {
91 0 : x = NS_MIN(x, aRect.X());
92 0 : xmost = NS_MAX(xmost, aRect.XMost());
93 : } else {
94 0 : x = aRect.X();
95 0 : xmost = aRect.XMost();
96 0 : mAssigned = true;
97 : }
98 0 : }
99 0 : nscoord Width() { return xmost - x; }
100 : nscoord x;
101 : nscoord xmost;
102 : bool mAssigned;
103 : };
104 :
105 : struct InnerClipEdges {
106 0 : InnerClipEdges() : mAssignedLeft(false), mAssignedRight(false) {}
107 0 : void AccumulateLeft(const nsRect& aRect) {
108 0 : if (NS_LIKELY(mAssignedLeft)) {
109 0 : mLeft = NS_MAX(mLeft, aRect.X());
110 : } else {
111 0 : mLeft = aRect.X();
112 0 : mAssignedLeft = true;
113 : }
114 0 : }
115 0 : void AccumulateRight(const nsRect& aRect) {
116 0 : if (NS_LIKELY(mAssignedRight)) {
117 0 : mRight = NS_MIN(mRight, aRect.XMost());
118 : } else {
119 0 : mRight = aRect.XMost();
120 0 : mAssignedRight = true;
121 : }
122 0 : }
123 : nscoord mLeft;
124 : nscoord mRight;
125 : bool mAssignedLeft;
126 : bool mAssignedRight;
127 : };
128 :
129 : /**
130 : * Examines frames on the line to determine whether we should draw a left
131 : * and/or right marker, and if so, which frames should be completely hidden
132 : * and the bounds of what will be displayed between the markers.
133 : * @param aLine the line we're processing
134 : * @param aFramesToHide frames that should have their display items removed
135 : * @param aAlignmentEdges the outermost edges of all text and atomic
136 : * inline-level frames that are inside the area between the markers
137 : */
138 : void ExamineLineFrames(nsLineBox* aLine,
139 : FrameHashtable* aFramesToHide,
140 : AlignmentEdges* aAlignmentEdges);
141 :
142 : /**
143 : * LineHasOverflowingText calls this to analyze edges, both the block's
144 : * content edges and the hypothetical marker edges aligned at the block edges.
145 : * @param aFrame the descendant frame of mBlock that we're analyzing
146 : * @param aContentArea the block's content area
147 : * @param aInsideMarkersArea the rectangle between the markers
148 : * @param aFramesToHide frames that should have their display items removed
149 : * @param aAlignmentEdges the outermost edges of all text and atomic
150 : * inline-level frames that are inside the area between the markers
151 : * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
152 : * inline-level frame is visible between the marker edges
153 : * @param aClippedMarkerEdges the innermost edges of all text and atomic
154 : * inline-level frames that are clipped by the current marker width
155 : */
156 : void ExamineFrameSubtree(nsIFrame* aFrame,
157 : const nsRect& aContentArea,
158 : const nsRect& aInsideMarkersArea,
159 : FrameHashtable* aFramesToHide,
160 : AlignmentEdges* aAlignmentEdges,
161 : bool* aFoundVisibleTextOrAtomic,
162 : InnerClipEdges* aClippedMarkerEdges);
163 :
164 : /**
165 : * ExamineFrameSubtree calls this to analyze a frame against the hypothetical
166 : * marker edges (aInsideMarkersArea) for text frames and atomic inline-level
167 : * elements. A text frame adds its extent inside aInsideMarkersArea where
168 : * grapheme clusters are fully visible. An atomic adds its border box if
169 : * it's fully inside aInsideMarkersArea, otherwise the frame is added to
170 : * aFramesToHide.
171 : * @param aFrame the descendant frame of mBlock that we're analyzing
172 : * @param aFrameType aFrame's frame type
173 : * @param aInsideMarkersArea the rectangle between the markers
174 : * @param aFramesToHide frames that should have their display items removed
175 : * @param aAlignmentEdges the outermost edges of all text and atomic
176 : * inline-level frames that are inside the area between the markers
177 : * inside aInsideMarkersArea
178 : * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
179 : * inline-level frame is visible between the marker edges
180 : * @param aClippedMarkerEdges the innermost edges of all text and atomic
181 : * inline-level frames that are clipped by the current marker width
182 : */
183 : void AnalyzeMarkerEdges(nsIFrame* aFrame,
184 : const nsIAtom* aFrameType,
185 : const nsRect& aInsideMarkersArea,
186 : FrameHashtable* aFramesToHide,
187 : AlignmentEdges* aAlignmentEdges,
188 : bool* aFoundVisibleTextOrAtomic,
189 : InnerClipEdges* aClippedMarkerEdges);
190 :
191 : /**
192 : * Clip or remove items given the final marker edges. ("clip" here just means
193 : * assigning mLeftEdge/mRightEdge for any nsCharClipDisplayItem that needs it,
194 : * see nsDisplayList.h for a description of that item).
195 : * @param aFramesToHide remove display items for these frames
196 : * @param aInsideMarkersArea is the area inside the markers
197 : */
198 : void PruneDisplayListContents(nsDisplayList* aList,
199 : const FrameHashtable& aFramesToHide,
200 : const nsRect& aInsideMarkersArea);
201 :
202 : /**
203 : * ProcessLine calls this to create display items for the markers and insert
204 : * them into a display list for the block.
205 : * @param aLine the line we're processing
206 : * @param aCreateLeft if true, create a marker on the left side
207 : * @param aCreateRight if true, create a marker on the right side
208 : * @param aInsideMarkersArea is the area inside the markers
209 : */
210 : void CreateMarkers(const nsLineBox* aLine,
211 : bool aCreateLeft,
212 : bool aCreateRight,
213 : const nsRect& aInsideMarkersArea) const;
214 :
215 : nsRect mContentArea;
216 : nsDisplayListBuilder* mBuilder;
217 : nsIFrame* mBlock;
218 : nsIScrollableFrame* mScrollableFrame;
219 : nsDisplayList* mMarkerList;
220 : bool mBlockIsRTL;
221 : bool mCanHaveHorizontalScrollbar;
222 : bool mAdjustForPixelSnapping;
223 :
224 0 : class Marker {
225 : public:
226 0 : void Init(const nsStyleTextOverflowSide& aStyle) {
227 0 : mInitialized = false;
228 0 : mWidth = 0;
229 0 : mStyle = &aStyle;
230 0 : }
231 :
232 : /**
233 : * Setup the marker string and calculate its size, if not done already.
234 : */
235 : void SetupString(nsIFrame* aFrame);
236 :
237 0 : bool IsNeeded() const {
238 0 : return mHasOverflow;
239 : }
240 0 : void Reset() {
241 0 : mHasOverflow = false;
242 0 : }
243 :
244 : // The current width of the marker, the range is [0 .. mIntrinsicWidth].
245 : nscoord mWidth;
246 : // The intrinsic width of the marker string.
247 : nscoord mIntrinsicWidth;
248 : // The marker text.
249 : nsString mMarkerString;
250 : // The style for this side.
251 : const nsStyleTextOverflowSide* mStyle;
252 : // True if there is visible overflowing inline content on this side.
253 : bool mHasOverflow;
254 : // True if mMarkerString and mWidth have been setup from style.
255 : bool mInitialized;
256 : // True if the style is text-overflow:clip on this side and the marker
257 : // won't cause the line to become empty.
258 : bool mActive;
259 : };
260 :
261 : Marker mLeft; // the horizontal left marker
262 : Marker mRight; // the horizontal right marker
263 : };
264 :
265 : } // namespace css
266 : } // namespace mozilla
267 :
268 : #endif /* !defined(TextOverflow_h_) */
|