diff -r 000000000000 -r 6474c204b198 layout/generic/TextOverflow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layout/generic/TextOverflow.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,241 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TextOverflow_h_ +#define TextOverflow_h_ + +#include "nsDisplayList.h" +#include "nsTHashtable.h" +#include "mozilla/Likely.h" +#include + +class nsIScrollableFrame; +class gfxTextRun; +class nsLineBox; + +namespace mozilla { +namespace css { + +/** + * A class for rendering CSS3 text-overflow. + * Usage: + * 1. allocate an object using WillProcessLines + * 2. then call ProcessLine for each line you are building display lists for + */ +class TextOverflow { + public: + /** + * Allocate an object for text-overflow processing. + * @return nullptr if no processing is necessary. The caller owns the object. + */ + static TextOverflow* WillProcessLines(nsDisplayListBuilder* aBuilder, + nsIFrame* aBlockFrame); + /** + * Analyze the display lists for text overflow and what kind of item is at + * the content edges. Add display items for text-overflow markers as needed + * and remove or clip items that would overlap a marker. + */ + void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine); + + /** + * Get the resulting text-overflow markers (the list may be empty). + * @return a DisplayList containing any text-overflow markers. + */ + nsDisplayList& GetMarkers() { return mMarkerList; } + + /** + * @return true if aBlockFrame needs analysis for text overflow. + */ + static bool CanHaveTextOverflow(nsDisplayListBuilder* aBuilder, + nsIFrame* aBlockFrame); + + typedef nsTHashtable > FrameHashtable; + + protected: + TextOverflow() {} + void Init(nsDisplayListBuilder* aBuilder, + nsIFrame* aBlockFrame); + + struct AlignmentEdges { + AlignmentEdges() : mAssigned(false) {} + void Accumulate(const nsRect& aRect) { + if (MOZ_LIKELY(mAssigned)) { + x = std::min(x, aRect.X()); + xmost = std::max(xmost, aRect.XMost()); + } else { + x = aRect.X(); + xmost = aRect.XMost(); + mAssigned = true; + } + } + nscoord Width() { return xmost - x; } + nscoord x; + nscoord xmost; + bool mAssigned; + }; + + struct InnerClipEdges { + InnerClipEdges() : mAssignedLeft(false), mAssignedRight(false) {} + void AccumulateLeft(const nsRect& aRect) { + if (MOZ_LIKELY(mAssignedLeft)) { + mLeft = std::max(mLeft, aRect.X()); + } else { + mLeft = aRect.X(); + mAssignedLeft = true; + } + } + void AccumulateRight(const nsRect& aRect) { + if (MOZ_LIKELY(mAssignedRight)) { + mRight = std::min(mRight, aRect.XMost()); + } else { + mRight = aRect.XMost(); + mAssignedRight = true; + } + } + nscoord mLeft; + nscoord mRight; + bool mAssignedLeft; + bool mAssignedRight; + }; + + /** + * Examines frames on the line to determine whether we should draw a left + * and/or right marker, and if so, which frames should be completely hidden + * and the bounds of what will be displayed between the markers. + * @param aLine the line we're processing + * @param aFramesToHide frames that should have their display items removed + * @param aAlignmentEdges the outermost edges of all text and atomic + * inline-level frames that are inside the area between the markers + */ + void ExamineLineFrames(nsLineBox* aLine, + FrameHashtable* aFramesToHide, + AlignmentEdges* aAlignmentEdges); + + /** + * LineHasOverflowingText calls this to analyze edges, both the block's + * content edges and the hypothetical marker edges aligned at the block edges. + * @param aFrame the descendant frame of mBlock that we're analyzing + * @param aContentArea the block's content area + * @param aInsideMarkersArea the rectangle between the markers + * @param aFramesToHide frames that should have their display items removed + * @param aAlignmentEdges the outermost edges of all text and atomic + * inline-level frames that are inside the area between the markers + * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic + * inline-level frame is visible between the marker edges + * @param aClippedMarkerEdges the innermost edges of all text and atomic + * inline-level frames that are clipped by the current marker width + */ + void ExamineFrameSubtree(nsIFrame* aFrame, + const nsRect& aContentArea, + const nsRect& aInsideMarkersArea, + FrameHashtable* aFramesToHide, + AlignmentEdges* aAlignmentEdges, + bool* aFoundVisibleTextOrAtomic, + InnerClipEdges* aClippedMarkerEdges); + + /** + * ExamineFrameSubtree calls this to analyze a frame against the hypothetical + * marker edges (aInsideMarkersArea) for text frames and atomic inline-level + * elements. A text frame adds its extent inside aInsideMarkersArea where + * grapheme clusters are fully visible. An atomic adds its border box if + * it's fully inside aInsideMarkersArea, otherwise the frame is added to + * aFramesToHide. + * @param aFrame the descendant frame of mBlock that we're analyzing + * @param aFrameType aFrame's frame type + * @param aInsideMarkersArea the rectangle between the markers + * @param aFramesToHide frames that should have their display items removed + * @param aAlignmentEdges the outermost edges of all text and atomic + * inline-level frames that are inside the area between the markers + * inside aInsideMarkersArea + * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic + * inline-level frame is visible between the marker edges + * @param aClippedMarkerEdges the innermost edges of all text and atomic + * inline-level frames that are clipped by the current marker width + */ + void AnalyzeMarkerEdges(nsIFrame* aFrame, + const nsIAtom* aFrameType, + const nsRect& aInsideMarkersArea, + FrameHashtable* aFramesToHide, + AlignmentEdges* aAlignmentEdges, + bool* aFoundVisibleTextOrAtomic, + InnerClipEdges* aClippedMarkerEdges); + + /** + * Clip or remove items given the final marker edges. ("clip" here just means + * assigning mLeftEdge/mRightEdge for any nsCharClipDisplayItem that needs it, + * see nsDisplayList.h for a description of that item). + * @param aFramesToHide remove display items for these frames + * @param aInsideMarkersArea is the area inside the markers + */ + void PruneDisplayListContents(nsDisplayList* aList, + const FrameHashtable& aFramesToHide, + const nsRect& aInsideMarkersArea); + + /** + * ProcessLine calls this to create display items for the markers and insert + * them into mMarkerList. + * @param aLine the line we're processing + * @param aCreateLeft if true, create a marker on the left side + * @param aCreateRight if true, create a marker on the right side + * @param aInsideMarkersArea is the area inside the markers + */ + void CreateMarkers(const nsLineBox* aLine, + bool aCreateLeft, + bool aCreateRight, + const nsRect& aInsideMarkersArea); + + nsRect mContentArea; + nsDisplayListBuilder* mBuilder; + nsIFrame* mBlock; + nsIScrollableFrame* mScrollableFrame; + nsDisplayList mMarkerList; + bool mBlockIsRTL; + bool mCanHaveHorizontalScrollbar; + bool mAdjustForPixelSnapping; + + class Marker { + public: + void Init(const nsStyleTextOverflowSide& aStyle) { + mInitialized = false; + mWidth = 0; + mStyle = &aStyle; + } + + /** + * Setup the marker string and calculate its size, if not done already. + */ + void SetupString(nsIFrame* aFrame); + + bool IsNeeded() const { + return mHasOverflow; + } + void Reset() { + mHasOverflow = false; + } + + // The current width of the marker, the range is [0 .. mIntrinsicWidth]. + nscoord mWidth; + // The intrinsic width of the marker. + nscoord mIntrinsicWidth; + // The style for this side. + const nsStyleTextOverflowSide* mStyle; + // True if there is visible overflowing inline content on this side. + bool mHasOverflow; + // True if mMarkerString and mWidth have been setup from style. + bool mInitialized; + // True if the style is text-overflow:clip on this side and the marker + // won't cause the line to become empty. + bool mActive; + }; + + Marker mLeft; // the horizontal left marker + Marker mRight; // the horizontal right marker +}; + +} // namespace css +} // namespace mozilla + +#endif /* !defined(TextOverflow_h_) */