2011-06-22 22:11:48 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2011-06-22 22:11:48 +04:00
|
|
|
|
|
|
|
#ifndef TextOverflow_h_
|
|
|
|
#define TextOverflow_h_
|
|
|
|
|
|
|
|
#include "nsDisplayList.h"
|
|
|
|
#include "nsTHashtable.h"
|
2012-10-26 17:32:10 +04:00
|
|
|
#include "mozilla/Likely.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2013-03-08 14:41:31 +04:00
|
|
|
|
2012-01-28 07:35:59 +04:00
|
|
|
class nsIScrollableFrame;
|
2013-03-08 14:41:31 +04:00
|
|
|
class gfxTextRun;
|
2013-08-22 22:32:52 +04:00
|
|
|
class nsLineBox;
|
2011-06-22 22:11:48 +04:00
|
|
|
|
|
|
|
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.
|
2012-07-30 18:20:58 +04:00
|
|
|
* @return nullptr if no processing is necessary. The caller owns the object.
|
2011-06-22 22:11:48 +04:00
|
|
|
*/
|
|
|
|
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);
|
|
|
|
|
2012-07-23 10:08:20 +04:00
|
|
|
/**
|
|
|
|
* Get the resulting text-overflow markers (the list may be empty).
|
|
|
|
* @return a DisplayList containing any text-overflow markers.
|
|
|
|
*/
|
|
|
|
nsDisplayList& GetMarkers() { return mMarkerList; }
|
|
|
|
|
2011-06-22 22:11:48 +04:00
|
|
|
/**
|
|
|
|
* @return true if aBlockFrame needs analysis for text overflow.
|
|
|
|
*/
|
|
|
|
static bool CanHaveTextOverflow(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aBlockFrame);
|
|
|
|
|
|
|
|
typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
TextOverflow() {}
|
2012-01-28 07:35:59 +04:00
|
|
|
void Init(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aBlockFrame);
|
2011-06-22 22:11:48 +04:00
|
|
|
|
|
|
|
struct AlignmentEdges {
|
|
|
|
AlignmentEdges() : mAssigned(false) {}
|
|
|
|
void Accumulate(const nsRect& aRect) {
|
2012-10-26 17:32:10 +04:00
|
|
|
if (MOZ_LIKELY(mAssigned)) {
|
2013-01-15 16:22:03 +04:00
|
|
|
x = std::min(x, aRect.X());
|
|
|
|
xmost = std::max(xmost, aRect.XMost());
|
2011-06-22 22:11:48 +04:00
|
|
|
} else {
|
|
|
|
x = aRect.X();
|
|
|
|
xmost = aRect.XMost();
|
|
|
|
mAssigned = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nscoord Width() { return xmost - x; }
|
|
|
|
nscoord x;
|
|
|
|
nscoord xmost;
|
|
|
|
bool mAssigned;
|
|
|
|
};
|
|
|
|
|
2011-12-19 18:48:31 +04:00
|
|
|
struct InnerClipEdges {
|
|
|
|
InnerClipEdges() : mAssignedLeft(false), mAssignedRight(false) {}
|
|
|
|
void AccumulateLeft(const nsRect& aRect) {
|
2012-10-26 17:32:10 +04:00
|
|
|
if (MOZ_LIKELY(mAssignedLeft)) {
|
2013-01-15 16:22:03 +04:00
|
|
|
mLeft = std::max(mLeft, aRect.X());
|
2011-12-19 18:48:31 +04:00
|
|
|
} else {
|
|
|
|
mLeft = aRect.X();
|
|
|
|
mAssignedLeft = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void AccumulateRight(const nsRect& aRect) {
|
2012-10-26 17:32:10 +04:00
|
|
|
if (MOZ_LIKELY(mAssignedRight)) {
|
2013-01-15 16:22:03 +04:00
|
|
|
mRight = std::min(mRight, aRect.XMost());
|
2011-12-19 18:48:31 +04:00
|
|
|
} else {
|
|
|
|
mRight = aRect.XMost();
|
|
|
|
mAssignedRight = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nscoord mLeft;
|
|
|
|
nscoord mRight;
|
|
|
|
bool mAssignedLeft;
|
|
|
|
bool mAssignedRight;
|
|
|
|
};
|
|
|
|
|
2011-06-22 22:11:48 +04:00
|
|
|
/**
|
|
|
|
* 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
|
2011-12-19 18:48:31 +04:00
|
|
|
* @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
|
|
|
|
* inline-level frame is visible between the marker edges
|
2011-12-19 18:48:31 +04:00
|
|
|
* @param aClippedMarkerEdges the innermost edges of all text and atomic
|
|
|
|
* inline-level frames that are clipped by the current marker width
|
2011-06-22 22:11:48 +04:00
|
|
|
*/
|
|
|
|
void ExamineFrameSubtree(nsIFrame* aFrame,
|
|
|
|
const nsRect& aContentArea,
|
|
|
|
const nsRect& aInsideMarkersArea,
|
|
|
|
FrameHashtable* aFramesToHide,
|
2011-12-19 18:48:31 +04:00
|
|
|
AlignmentEdges* aAlignmentEdges,
|
2011-12-19 18:48:31 +04:00
|
|
|
bool* aFoundVisibleTextOrAtomic,
|
|
|
|
InnerClipEdges* aClippedMarkerEdges);
|
2011-06-22 22:11:48 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2011-12-19 18:48:31 +04:00
|
|
|
* @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
|
|
|
|
* inline-level frame is visible between the marker edges
|
2011-12-19 18:48:31 +04:00
|
|
|
* @param aClippedMarkerEdges the innermost edges of all text and atomic
|
|
|
|
* inline-level frames that are clipped by the current marker width
|
2011-06-22 22:11:48 +04:00
|
|
|
*/
|
|
|
|
void AnalyzeMarkerEdges(nsIFrame* aFrame,
|
|
|
|
const nsIAtom* aFrameType,
|
|
|
|
const nsRect& aInsideMarkersArea,
|
|
|
|
FrameHashtable* aFramesToHide,
|
2011-12-19 18:48:31 +04:00
|
|
|
AlignmentEdges* aAlignmentEdges,
|
2011-12-19 18:48:31 +04:00
|
|
|
bool* aFoundVisibleTextOrAtomic,
|
|
|
|
InnerClipEdges* aClippedMarkerEdges);
|
2011-06-22 22:11:48 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2012-07-23 10:08:20 +04:00
|
|
|
* them into mMarkerList.
|
2011-06-22 22:11:48 +04:00
|
|
|
* @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,
|
2012-07-23 10:08:20 +04:00
|
|
|
const nsRect& aInsideMarkersArea);
|
2011-06-22 22:11:48 +04:00
|
|
|
|
|
|
|
nsRect mContentArea;
|
|
|
|
nsDisplayListBuilder* mBuilder;
|
|
|
|
nsIFrame* mBlock;
|
2012-01-28 07:35:59 +04:00
|
|
|
nsIScrollableFrame* mScrollableFrame;
|
2012-07-23 10:08:20 +04:00
|
|
|
nsDisplayList mMarkerList;
|
2011-06-22 22:11:48 +04:00
|
|
|
bool mBlockIsRTL;
|
|
|
|
bool mCanHaveHorizontalScrollbar;
|
2012-01-28 07:35:59 +04:00
|
|
|
bool mAdjustForPixelSnapping;
|
2011-06-22 22:11:48 +04:00
|
|
|
|
|
|
|
class Marker {
|
|
|
|
public:
|
2011-08-21 00:41:39 +04:00
|
|
|
void Init(const nsStyleTextOverflowSide& aStyle) {
|
2011-06-22 22:11:48 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-12-19 18:48:31 +04:00
|
|
|
// The current width of the marker, the range is [0 .. mIntrinsicWidth].
|
2011-06-22 22:11:48 +04:00
|
|
|
nscoord mWidth;
|
2013-03-08 14:41:31 +04:00
|
|
|
// The intrinsic width of the marker.
|
2011-12-19 18:48:31 +04:00
|
|
|
nscoord mIntrinsicWidth;
|
2011-06-22 22:11:48 +04:00
|
|
|
// The style for this side.
|
2011-08-21 00:41:39 +04:00
|
|
|
const nsStyleTextOverflowSide* mStyle;
|
2011-06-22 22:11:48 +04:00
|
|
|
// 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;
|
2011-12-19 18:48:31 +04:00
|
|
|
// True if the style is text-overflow:clip on this side and the marker
|
|
|
|
// won't cause the line to become empty.
|
2011-12-19 18:48:30 +04:00
|
|
|
bool mActive;
|
2011-06-22 22:11:48 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
Marker mLeft; // the horizontal left marker
|
|
|
|
Marker mRight; // the horizontal right marker
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace css
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif /* !defined(TextOverflow_h_) */
|