Skip to content

Commit

Permalink
Bug 1203871 - Part 1. Add nsIFrame::GetCharacterRectsInRange. r=jfkthame
Browse files Browse the repository at this point in the history
Masayuki suggests GetCharcterRectsInRange instead of first idea's API by part 2 implementation.

IME wants to need the width per character.  Now nsTextFrame/nsIFrmae has only API to get point of string.  So I want to add this method to calculate simply by comment #3.

If no text frame,  I would like to return error due to no character.  (Caller shouldn't call this API on non-text frame.)

MozReview-Commit-ID: LQHUTzhnGn

--HG--
extra : rebase_source : bc495493c7be73afb05489ad2169e8dcdd6e6da4
extra : histedit_source : e54a7c3bfb100765317a0c8a83b432d5f706ffe1
  • Loading branch information
makotokato committed Jun 23, 2016
1 parent 841e0f3 commit fb90c35
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 38 deletions.
8 changes: 8 additions & 0 deletions layout/generic/nsFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6606,6 +6606,14 @@ nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint)
return NS_OK;
}

nsresult
nsFrame::GetCharacterRectsInRange(int32_t aInOffset, int32_t aLength,
nsTArray<nsRect>& aOutRect)
{
/* no text */
return NS_ERROR_FAILURE;
}

nsresult
nsFrame::GetChildFrameContainingOffset(int32_t inContentOffset, bool inHint, int32_t* outFrameContentOffset, nsIFrame **outChildFrame)
{
Expand Down
3 changes: 3 additions & 0 deletions layout/generic/nsFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ class nsFrame : public nsBox

virtual nsresult GetPointFromOffset(int32_t inOffset,
nsPoint* outPoint) override;
virtual nsresult GetCharacterRectsInRange(int32_t aInOffset,
int32_t aLength,
nsTArray<nsRect>& aOutRect) override;

virtual nsresult GetChildFrameContainingOffset(int32_t inContentOffset,
bool inHint,
Expand Down
8 changes: 8 additions & 0 deletions layout/generic/nsIFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,14 @@ class nsIFrame : public nsQueryFrame
*/
virtual nsresult GetPointFromOffset(int32_t inOffset,
nsPoint* outPoint) = 0;

/**
* Get a list of character rects in a given range.
* This is similar version of GetPointFromOffset.
*/
virtual nsresult GetCharacterRectsInRange(int32_t aInOffset,
int32_t aLength,
nsTArray<nsRect>& aRects) = 0;

/**
* Get the child frame of this frame which contains the given
Expand Down
175 changes: 137 additions & 38 deletions layout/generic/nsTextFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2959,9 +2959,9 @@ class MOZ_STACK_CLASS PropertyProvider : public gfxTextRun::PropertyProvider {
// This may not be equal to the frame offset/length in because we may have
// adjusted for whitespace trimming according to the state bits set in the frame
// (for the static provider)
const gfxSkipCharsIterator& GetStart() { return mStart; }
const gfxSkipCharsIterator& GetStart() const { return mStart; }
// May return INT32_MAX if that was given to the constructor
uint32_t GetOriginalLength() {
uint32_t GetOriginalLength() const {
NS_ASSERTION(mLength != INT32_MAX, "Length not known");
return mLength;
}
Expand Down Expand Up @@ -7177,21 +7177,79 @@ nsTextFrame::SetSelectedRange(uint32_t aStart, uint32_t aEnd, bool aSelected,
}
}

void
nsTextFrame::UpdateIteratorFromOffset(const PropertyProvider& aProperties,
int32_t& aInOffset,
gfxSkipCharsIterator& aIter)
{
if (aInOffset < GetContentOffset()){
NS_WARNING("offset before this frame's content");
aInOffset = GetContentOffset();
} else if (aInOffset > GetContentEnd()) {
NS_WARNING("offset after this frame's content");
aInOffset = GetContentEnd();
}

int32_t trimmedOffset = aProperties.GetStart().GetOriginalOffset();
int32_t trimmedEnd = trimmedOffset + aProperties.GetOriginalLength();
aInOffset = std::max(aInOffset, trimmedOffset);
aInOffset = std::min(aInOffset, trimmedEnd);

aIter.SetOriginalOffset(aInOffset);

if (aInOffset < trimmedEnd &&
!aIter.IsOriginalCharSkipped() &&
!mTextRun->IsClusterStart(aIter.GetSkippedOffset())) {
NS_WARNING("called for non-cluster boundary");
FindClusterStart(mTextRun, trimmedOffset, &aIter);
}
}

nsPoint
nsTextFrame::GetPointFromIterator(const gfxSkipCharsIterator& aIter,
PropertyProvider& aProperties)
{
Range range(aProperties.GetStart().GetSkippedOffset(),
aIter.GetSkippedOffset());
gfxFloat advance = mTextRun->GetAdvanceWidth(range, &aProperties);
nscoord iSize = NSToCoordCeilClamped(advance);
nsPoint point;

if (mTextRun->IsVertical()) {
point.x = 0;
if (mTextRun->IsInlineReversed()) {
point.y = mRect.height - iSize;
} else {
point.y = iSize;
}
} else {
point.y = 0;
if (mTextRun->IsInlineReversed()) {
point.x = mRect.width - iSize;
} else {
point.x = iSize;
}
if (StyleContext()->IsTextCombined()) {
point.x *= GetTextCombineScaleFactor(this);
}
}
return point;
}

nsresult
nsTextFrame::GetPointFromOffset(int32_t inOffset,
nsPoint* outPoint)
{
if (!outPoint)
return NS_ERROR_NULL_POINTER;

outPoint->x = 0;
outPoint->y = 0;

DEBUG_VERIFY_NOT_DIRTY(mState);
if (mState & NS_FRAME_IS_DIRTY)
return NS_ERROR_UNEXPECTED;

if (GetContentLength() <= 0) {
outPoint->x = 0;
outPoint->y = 0;
return NS_OK;
}

Expand All @@ -7202,49 +7260,90 @@ nsTextFrame::GetPointFromOffset(int32_t inOffset,
PropertyProvider properties(this, iter, nsTextFrame::eInflated);
// Don't trim trailing whitespace, we want the caret to appear in the right
// place if it's positioned there
properties.InitializeForDisplay(false);
properties.InitializeForDisplay(false);

if (inOffset < GetContentOffset()){
NS_WARNING("offset before this frame's content");
inOffset = GetContentOffset();
} else if (inOffset > GetContentEnd()) {
NS_WARNING("offset after this frame's content");
inOffset = GetContentEnd();
UpdateIteratorFromOffset(properties, inOffset, iter);

*outPoint = GetPointFromIterator(iter, properties);

return NS_OK;
}

nsresult
nsTextFrame::GetCharacterRectsInRange(int32_t aInOffset,
int32_t aLength,
nsTArray<nsRect>& aRects)
{
DEBUG_VERIFY_NOT_DIRTY(mState);
if (mState & NS_FRAME_IS_DIRTY) {
return NS_ERROR_UNEXPECTED;
}
int32_t trimmedOffset = properties.GetStart().GetOriginalOffset();
int32_t trimmedEnd = trimmedOffset + properties.GetOriginalLength();
inOffset = std::max(inOffset, trimmedOffset);
inOffset = std::min(inOffset, trimmedEnd);

iter.SetOriginalOffset(inOffset);
if (GetContentLength() <= 0) {
return NS_OK;
}

if (inOffset < trimmedEnd &&
!iter.IsOriginalCharSkipped() &&
!mTextRun->IsClusterStart(iter.GetSkippedOffset())) {
NS_WARNING("GetPointFromOffset called for non-cluster boundary");
FindClusterStart(mTextRun, trimmedOffset, &iter);
if (!mTextRun) {
return NS_ERROR_FAILURE;
}

Range range(properties.GetStart().GetSkippedOffset(),
iter.GetSkippedOffset());
gfxFloat advance = mTextRun->GetAdvanceWidth(range, &properties);
nscoord iSize = NSToCoordCeilClamped(advance);
gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated);
PropertyProvider properties(this, iter, nsTextFrame::eInflated);
// Don't trim trailing whitespace, we want the caret to appear in the right
// place if it's positioned there
properties.InitializeForDisplay(false);

if (mTextRun->IsVertical()) {
if (mTextRun->IsInlineReversed()) {
outPoint->y = mRect.height - iSize;
} else {
outPoint->y = iSize;
UpdateIteratorFromOffset(properties, aInOffset, iter);

for (int32_t i = 0; i < aLength; i++) {
if (aInOffset > GetContentEnd()) {
break;
}
} else {
if (mTextRun->IsInlineReversed()) {
outPoint->x = mRect.width - iSize;
} else {
outPoint->x = iSize;

if (!iter.IsOriginalCharSkipped() &&
!mTextRun->IsClusterStart(iter.GetSkippedOffset())) {
FindClusterStart(mTextRun,
properties.GetStart().GetOriginalOffset() +
properties.GetOriginalLength(),
&iter);
}
if (StyleContext()->IsTextCombined()) {
outPoint->x *= GetTextCombineScaleFactor(this);

nsPoint point = GetPointFromIterator(iter, properties);
nsRect rect;
rect.x = point.x;
rect.y = point.y;

nscoord iSize = 0;
gfxSkipCharsIterator nextIter(iter);
if (aInOffset < GetContentEnd()) {
nextIter.AdvanceOriginal(1);
if (!nextIter.IsOriginalCharSkipped() &&
!mTextRun->IsClusterStart(nextIter.GetSkippedOffset())) {
FindClusterEnd(mTextRun, GetContentEnd(), &nextIter);
}

gfxFloat advance =
mTextRun->GetAdvanceWidth(Range(iter.GetSkippedOffset(),
nextIter.GetSkippedOffset()),
&properties);
iSize = NSToCoordCeilClamped(advance);
}

if (mTextRun->IsVertical()) {
rect.width = mRect.width;
rect.height = iSize;
} else {
rect.width = iSize;
rect.height = mRect.height;

if (StyleContext()->IsTextCombined()) {
rect.width *= GetTextCombineScaleFactor(this);
}
}
aRects.AppendElement(rect);

iter.AdvanceOriginal(1);
aInOffset++;
}

return NS_OK;
Expand Down
15 changes: 15 additions & 0 deletions layout/generic/nsTextFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ class nsTextFrame : public nsFrame {

virtual nsresult GetPointFromOffset(int32_t inOffset,
nsPoint* outPoint) override;
virtual nsresult GetCharacterRectsInRange(int32_t aInOffset,
int32_t aLength,
nsTArray<nsRect>& aRects) override;

virtual nsresult GetChildFrameContainingOffset(int32_t inContentOffset,
bool inHint,
Expand Down Expand Up @@ -792,6 +795,18 @@ class nsTextFrame : public nsFrame {
virtual bool HasAnyNoncollapsedCharacters() override;

void ClearMetrics(nsHTMLReflowMetrics& aMetrics);

/**
* UpdateIteratorFromOffset() updates the iterator from a given offset.
* Also, aInOffset may be updated to cluster start if aInOffset isn't
* the offset of cluster start.
*/
void UpdateIteratorFromOffset(const PropertyProvider& aProperties,
int32_t& aInOffset,
gfxSkipCharsIterator& aIter);

nsPoint GetPointFromIterator(const gfxSkipCharsIterator& aIter,
PropertyProvider& aProperties);
};

#endif

0 comments on commit fb90c35

Please sign in to comment.