layout/generic/TextOverflow.h

changeset 0
6474c204b198
     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_) */

mercurial