1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/generic/TextOverflow.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,241 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef TextOverflow_h_ 1.11 +#define TextOverflow_h_ 1.12 + 1.13 +#include "nsDisplayList.h" 1.14 +#include "nsTHashtable.h" 1.15 +#include "mozilla/Likely.h" 1.16 +#include <algorithm> 1.17 + 1.18 +class nsIScrollableFrame; 1.19 +class gfxTextRun; 1.20 +class nsLineBox; 1.21 + 1.22 +namespace mozilla { 1.23 +namespace css { 1.24 + 1.25 +/** 1.26 + * A class for rendering CSS3 text-overflow. 1.27 + * Usage: 1.28 + * 1. allocate an object using WillProcessLines 1.29 + * 2. then call ProcessLine for each line you are building display lists for 1.30 + */ 1.31 +class TextOverflow { 1.32 + public: 1.33 + /** 1.34 + * Allocate an object for text-overflow processing. 1.35 + * @return nullptr if no processing is necessary. The caller owns the object. 1.36 + */ 1.37 + static TextOverflow* WillProcessLines(nsDisplayListBuilder* aBuilder, 1.38 + nsIFrame* aBlockFrame); 1.39 + /** 1.40 + * Analyze the display lists for text overflow and what kind of item is at 1.41 + * the content edges. Add display items for text-overflow markers as needed 1.42 + * and remove or clip items that would overlap a marker. 1.43 + */ 1.44 + void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine); 1.45 + 1.46 + /** 1.47 + * Get the resulting text-overflow markers (the list may be empty). 1.48 + * @return a DisplayList containing any text-overflow markers. 1.49 + */ 1.50 + nsDisplayList& GetMarkers() { return mMarkerList; } 1.51 + 1.52 + /** 1.53 + * @return true if aBlockFrame needs analysis for text overflow. 1.54 + */ 1.55 + static bool CanHaveTextOverflow(nsDisplayListBuilder* aBuilder, 1.56 + nsIFrame* aBlockFrame); 1.57 + 1.58 + typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable; 1.59 + 1.60 + protected: 1.61 + TextOverflow() {} 1.62 + void Init(nsDisplayListBuilder* aBuilder, 1.63 + nsIFrame* aBlockFrame); 1.64 + 1.65 + struct AlignmentEdges { 1.66 + AlignmentEdges() : mAssigned(false) {} 1.67 + void Accumulate(const nsRect& aRect) { 1.68 + if (MOZ_LIKELY(mAssigned)) { 1.69 + x = std::min(x, aRect.X()); 1.70 + xmost = std::max(xmost, aRect.XMost()); 1.71 + } else { 1.72 + x = aRect.X(); 1.73 + xmost = aRect.XMost(); 1.74 + mAssigned = true; 1.75 + } 1.76 + } 1.77 + nscoord Width() { return xmost - x; } 1.78 + nscoord x; 1.79 + nscoord xmost; 1.80 + bool mAssigned; 1.81 + }; 1.82 + 1.83 + struct InnerClipEdges { 1.84 + InnerClipEdges() : mAssignedLeft(false), mAssignedRight(false) {} 1.85 + void AccumulateLeft(const nsRect& aRect) { 1.86 + if (MOZ_LIKELY(mAssignedLeft)) { 1.87 + mLeft = std::max(mLeft, aRect.X()); 1.88 + } else { 1.89 + mLeft = aRect.X(); 1.90 + mAssignedLeft = true; 1.91 + } 1.92 + } 1.93 + void AccumulateRight(const nsRect& aRect) { 1.94 + if (MOZ_LIKELY(mAssignedRight)) { 1.95 + mRight = std::min(mRight, aRect.XMost()); 1.96 + } else { 1.97 + mRight = aRect.XMost(); 1.98 + mAssignedRight = true; 1.99 + } 1.100 + } 1.101 + nscoord mLeft; 1.102 + nscoord mRight; 1.103 + bool mAssignedLeft; 1.104 + bool mAssignedRight; 1.105 + }; 1.106 + 1.107 + /** 1.108 + * Examines frames on the line to determine whether we should draw a left 1.109 + * and/or right marker, and if so, which frames should be completely hidden 1.110 + * and the bounds of what will be displayed between the markers. 1.111 + * @param aLine the line we're processing 1.112 + * @param aFramesToHide frames that should have their display items removed 1.113 + * @param aAlignmentEdges the outermost edges of all text and atomic 1.114 + * inline-level frames that are inside the area between the markers 1.115 + */ 1.116 + void ExamineLineFrames(nsLineBox* aLine, 1.117 + FrameHashtable* aFramesToHide, 1.118 + AlignmentEdges* aAlignmentEdges); 1.119 + 1.120 + /** 1.121 + * LineHasOverflowingText calls this to analyze edges, both the block's 1.122 + * content edges and the hypothetical marker edges aligned at the block edges. 1.123 + * @param aFrame the descendant frame of mBlock that we're analyzing 1.124 + * @param aContentArea the block's content area 1.125 + * @param aInsideMarkersArea the rectangle between the markers 1.126 + * @param aFramesToHide frames that should have their display items removed 1.127 + * @param aAlignmentEdges the outermost edges of all text and atomic 1.128 + * inline-level frames that are inside the area between the markers 1.129 + * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic 1.130 + * inline-level frame is visible between the marker edges 1.131 + * @param aClippedMarkerEdges the innermost edges of all text and atomic 1.132 + * inline-level frames that are clipped by the current marker width 1.133 + */ 1.134 + void ExamineFrameSubtree(nsIFrame* aFrame, 1.135 + const nsRect& aContentArea, 1.136 + const nsRect& aInsideMarkersArea, 1.137 + FrameHashtable* aFramesToHide, 1.138 + AlignmentEdges* aAlignmentEdges, 1.139 + bool* aFoundVisibleTextOrAtomic, 1.140 + InnerClipEdges* aClippedMarkerEdges); 1.141 + 1.142 + /** 1.143 + * ExamineFrameSubtree calls this to analyze a frame against the hypothetical 1.144 + * marker edges (aInsideMarkersArea) for text frames and atomic inline-level 1.145 + * elements. A text frame adds its extent inside aInsideMarkersArea where 1.146 + * grapheme clusters are fully visible. An atomic adds its border box if 1.147 + * it's fully inside aInsideMarkersArea, otherwise the frame is added to 1.148 + * aFramesToHide. 1.149 + * @param aFrame the descendant frame of mBlock that we're analyzing 1.150 + * @param aFrameType aFrame's frame type 1.151 + * @param aInsideMarkersArea the rectangle between the markers 1.152 + * @param aFramesToHide frames that should have their display items removed 1.153 + * @param aAlignmentEdges the outermost edges of all text and atomic 1.154 + * inline-level frames that are inside the area between the markers 1.155 + * inside aInsideMarkersArea 1.156 + * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic 1.157 + * inline-level frame is visible between the marker edges 1.158 + * @param aClippedMarkerEdges the innermost edges of all text and atomic 1.159 + * inline-level frames that are clipped by the current marker width 1.160 + */ 1.161 + void AnalyzeMarkerEdges(nsIFrame* aFrame, 1.162 + const nsIAtom* aFrameType, 1.163 + const nsRect& aInsideMarkersArea, 1.164 + FrameHashtable* aFramesToHide, 1.165 + AlignmentEdges* aAlignmentEdges, 1.166 + bool* aFoundVisibleTextOrAtomic, 1.167 + InnerClipEdges* aClippedMarkerEdges); 1.168 + 1.169 + /** 1.170 + * Clip or remove items given the final marker edges. ("clip" here just means 1.171 + * assigning mLeftEdge/mRightEdge for any nsCharClipDisplayItem that needs it, 1.172 + * see nsDisplayList.h for a description of that item). 1.173 + * @param aFramesToHide remove display items for these frames 1.174 + * @param aInsideMarkersArea is the area inside the markers 1.175 + */ 1.176 + void PruneDisplayListContents(nsDisplayList* aList, 1.177 + const FrameHashtable& aFramesToHide, 1.178 + const nsRect& aInsideMarkersArea); 1.179 + 1.180 + /** 1.181 + * ProcessLine calls this to create display items for the markers and insert 1.182 + * them into mMarkerList. 1.183 + * @param aLine the line we're processing 1.184 + * @param aCreateLeft if true, create a marker on the left side 1.185 + * @param aCreateRight if true, create a marker on the right side 1.186 + * @param aInsideMarkersArea is the area inside the markers 1.187 + */ 1.188 + void CreateMarkers(const nsLineBox* aLine, 1.189 + bool aCreateLeft, 1.190 + bool aCreateRight, 1.191 + const nsRect& aInsideMarkersArea); 1.192 + 1.193 + nsRect mContentArea; 1.194 + nsDisplayListBuilder* mBuilder; 1.195 + nsIFrame* mBlock; 1.196 + nsIScrollableFrame* mScrollableFrame; 1.197 + nsDisplayList mMarkerList; 1.198 + bool mBlockIsRTL; 1.199 + bool mCanHaveHorizontalScrollbar; 1.200 + bool mAdjustForPixelSnapping; 1.201 + 1.202 + class Marker { 1.203 + public: 1.204 + void Init(const nsStyleTextOverflowSide& aStyle) { 1.205 + mInitialized = false; 1.206 + mWidth = 0; 1.207 + mStyle = &aStyle; 1.208 + } 1.209 + 1.210 + /** 1.211 + * Setup the marker string and calculate its size, if not done already. 1.212 + */ 1.213 + void SetupString(nsIFrame* aFrame); 1.214 + 1.215 + bool IsNeeded() const { 1.216 + return mHasOverflow; 1.217 + } 1.218 + void Reset() { 1.219 + mHasOverflow = false; 1.220 + } 1.221 + 1.222 + // The current width of the marker, the range is [0 .. mIntrinsicWidth]. 1.223 + nscoord mWidth; 1.224 + // The intrinsic width of the marker. 1.225 + nscoord mIntrinsicWidth; 1.226 + // The style for this side. 1.227 + const nsStyleTextOverflowSide* mStyle; 1.228 + // True if there is visible overflowing inline content on this side. 1.229 + bool mHasOverflow; 1.230 + // True if mMarkerString and mWidth have been setup from style. 1.231 + bool mInitialized; 1.232 + // True if the style is text-overflow:clip on this side and the marker 1.233 + // won't cause the line to become empty. 1.234 + bool mActive; 1.235 + }; 1.236 + 1.237 + Marker mLeft; // the horizontal left marker 1.238 + Marker mRight; // the horizontal right marker 1.239 +}; 1.240 + 1.241 +} // namespace css 1.242 +} // namespace mozilla 1.243 + 1.244 +#endif /* !defined(TextOverflow_h_) */