gecko/widget/ContentCache.cpp

203 lines
5.7 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
#include "mozilla/ContentCache.h"
#include "mozilla/TextEvents.h"
#include "nsIWidget.h"
namespace mozilla {
using namespace widget;
/*****************************************************************************
* mozilla::ContentCache
*****************************************************************************/
ContentCache::ContentCache()
: mCompositionStart(UINT32_MAX)
, mCompositionEventsDuringRequest(0)
, mIsComposing(false)
, mRequestedToCommitOrCancelComposition(false)
{
}
void
ContentCache::Clear()
{
mText.Truncate();
}
void
ContentCache::SetText(const nsAString& aText)
{
mText = aText;
}
void
ContentCache::SetSelection(uint32_t aAnchorOffset,
uint32_t aFocusOffset,
const WritingMode& aWritingMode)
{
mSelection.mAnchor = aAnchorOffset;
mSelection.mFocus = aFocusOffset;
mSelection.mWritingMode = aWritingMode;
}
bool
ContentCache::InitTextRectArray(uint32_t aOffset,
const RectArray& aTextRectArray)
{
if (NS_WARN_IF(aOffset >= TextLength()) ||
NS_WARN_IF(aOffset + aTextRectArray.Length() > TextLength())) {
return false;
}
mTextRectArray.mStart = aOffset;
mTextRectArray.mRects = aTextRectArray;
return true;
}
bool
ContentCache::GetTextRect(uint32_t aOffset,
LayoutDeviceIntRect& aTextRect) const
{
if (NS_WARN_IF(!mTextRectArray.InRange(aOffset))) {
aTextRect.SetEmpty();
return false;
}
aTextRect = mTextRectArray.GetRect(aOffset);
return true;
}
bool
ContentCache::GetUnionTextRects(uint32_t aOffset,
uint32_t aLength,
LayoutDeviceIntRect& aUnionTextRect) const
{
if (NS_WARN_IF(!mTextRectArray.InRange(aOffset, aLength))) {
aUnionTextRect.SetEmpty();
return false;
}
aUnionTextRect = mTextRectArray.GetUnionRect(aOffset, aLength);
return true;
}
bool
ContentCache::InitCaretRect(uint32_t aOffset,
const LayoutDeviceIntRect& aCaretRect)
{
if (NS_WARN_IF(aOffset > TextLength())) {
return false;
}
mCaret.mOffset = aOffset;
mCaret.mRect = aCaretRect;
return true;
}
bool
ContentCache::GetCaretRect(uint32_t aOffset,
LayoutDeviceIntRect& aCaretRect) const
{
if (mCaret.mOffset != aOffset) {
aCaretRect.SetEmpty();
return false;
}
aCaretRect = mCaret.mRect;
return true;
}
bool
ContentCache::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
{
if (!aEvent.CausesDOMTextEvent()) {
MOZ_ASSERT(aEvent.message == NS_COMPOSITION_START);
mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
mCompositionStart = SelectionStart();
// XXX What's this case??
if (mRequestedToCommitOrCancelComposition) {
mCommitStringByRequest = aEvent.mData;
mCompositionEventsDuringRequest++;
return false;
}
return true;
}
// XXX Why do we ignore following composition events here?
// TextComposition must handle following events correctly!
// During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION,
// widget usually sends a NS_COMPOSITION_CHANGE event to finalize or
// clear the composition, respectively.
// Because the event will not reach content in time, we intercept it
// here and pass the text as the DidRequestToCommitOrCancelComposition()
// return value.
if (mRequestedToCommitOrCancelComposition) {
mCommitStringByRequest = aEvent.mData;
mCompositionEventsDuringRequest++;
return false;
}
// We must be able to simulate the selection because
// we might not receive selection updates in time
if (!mIsComposing) {
mCompositionStart = SelectionStart();
}
// XXX This causes different behavior from non-e10s mode.
// Selection range should represent caret position in the composition
// string but this means selection range is all of the composition string.
SetSelection(mCompositionStart + aEvent.mData.Length(),
mSelection.mWritingMode);
mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
return true;
}
uint32_t
ContentCache::RequestToCommitComposition(nsIWidget* aWidget,
bool aCancel,
nsAString& aLastString)
{
mRequestedToCommitOrCancelComposition = true;
mCompositionEventsDuringRequest = 0;
aWidget->NotifyIME(IMENotification(aCancel ? REQUEST_TO_CANCEL_COMPOSITION :
REQUEST_TO_COMMIT_COMPOSITION));
mRequestedToCommitOrCancelComposition = false;
aLastString = mCommitStringByRequest;
mCommitStringByRequest.Truncate(0);
return mCompositionEventsDuringRequest;
}
/*****************************************************************************
* mozilla::ContentCache::TextRectArray
*****************************************************************************/
LayoutDeviceIntRect
ContentCache::TextRectArray::GetRect(uint32_t aOffset) const
{
LayoutDeviceIntRect rect;
if (InRange(aOffset)) {
rect = mRects[aOffset - mStart];
}
return rect;
}
LayoutDeviceIntRect
ContentCache::TextRectArray::GetUnionRect(uint32_t aOffset,
uint32_t aLength) const
{
LayoutDeviceIntRect rect;
if (!InRange(aOffset, aLength)) {
return rect;
}
for (uint32_t i = 0; i < aLength; i++) {
rect = rect.Union(mRects[aOffset - mStart + i]);
}
return rect;
}
} // namespace mozilla