diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 2ec2ef3275..0c8f14fbaa 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -1934,13 +1934,13 @@ nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, EventMessage message; switch (aType) { case QUERY_SELECTED_TEXT: - message = NS_QUERY_SELECTED_TEXT; + message = eQuerySelectedText; break; case QUERY_TEXT_CONTENT: - message = NS_QUERY_TEXT_CONTENT; + message = eQueryTextContent; break; case QUERY_CARET_RECT: - message = NS_QUERY_CARET_RECT; + message = eQueryCaretRect; break; case QUERY_TEXT_RECT: message = NS_QUERY_TEXT_RECT; @@ -1992,10 +1992,10 @@ nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, InitEvent(queryEvent, &pt); switch (message) { - case NS_QUERY_TEXT_CONTENT: + case eQueryTextContent: queryEvent.InitForQueryTextContent(aOffset, aLength, useNativeLineBreak); break; - case NS_QUERY_CARET_RECT: + case eQueryCaretRect: queryEvent.InitForQueryCaretRect(aOffset, useNativeLineBreak); break; case NS_QUERY_TEXT_RECT: @@ -2033,7 +2033,7 @@ nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset, return NS_ERROR_FAILURE; } - WidgetSelectionEvent selectionEvent(true, NS_SELECTION_SET, widget); + WidgetSelectionEvent selectionEvent(true, eSetSelection, widget); InitEvent(selectionEvent); selectionEvent.mOffset = aOffset; diff --git a/dom/base/nsISelectionController.idl b/dom/base/nsISelectionController.idl index 01bbc48312..c3b4c77cb0 100644 --- a/dom/base/nsISelectionController.idl +++ b/dom/base/nsISelectionController.idl @@ -16,7 +16,7 @@ interface nsIDOMNode; interface nsISelection; interface nsISelectionDisplay; -[scriptable, uuid(82c3a9df-9bd6-4da2-b561-d85a9eec5caa)] +[scriptable, uuid(e5238312-2f50-4ec1-8e23-6337f3a67727)] interface nsISelectionController : nsISelectionDisplay { const short SELECTION_NONE=0; @@ -29,7 +29,8 @@ interface nsISelectionController : nsISelectionDisplay const short SELECTION_ACCESSIBILITY=64; // For accessibility API usage const short SELECTION_FIND=128; const short SELECTION_URLSECONDARY=256; - const short NUM_SELECTIONTYPES=10; + const short SELECTION_URLSTRIKEOUT=512; + const short NUM_SELECTIONTYPES=11; const short SELECTION_ANCHOR_REGION = 0; const short SELECTION_FOCUS_REGION = 1; diff --git a/dom/base/nsQueryContentEventResult.cpp b/dom/base/nsQueryContentEventResult.cpp index a882aeeabe..f293ec8911 100644 --- a/dom/base/nsQueryContentEventResult.cpp +++ b/dom/base/nsQueryContentEventResult.cpp @@ -19,8 +19,9 @@ NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsQueryContentEventResult) NS_IMPL_RELEASE(nsQueryContentEventResult) -nsQueryContentEventResult::nsQueryContentEventResult() : - mEventID(0), mSucceeded(false) +nsQueryContentEventResult::nsQueryContentEventResult() + : mEventMessage(eVoidEvent) + , mSucceeded(false) { } @@ -54,20 +55,19 @@ nsQueryContentEventResult::GetTentativeCaretOffset(uint32_t* aOffset) return NS_OK; } -static bool IsRectEnabled(uint32_t aEventID) +static bool IsRectEnabled(EventMessage aEventMessage) { - return aEventID == NS_QUERY_CARET_RECT || - aEventID == NS_QUERY_TEXT_RECT || - aEventID == NS_QUERY_EDITOR_RECT || - aEventID == NS_QUERY_CHARACTER_AT_POINT; + return aEventMessage == eQueryCaretRect || + aEventMessage == NS_QUERY_TEXT_RECT || + aEventMessage == NS_QUERY_EDITOR_RECT || + aEventMessage == NS_QUERY_CHARACTER_AT_POINT; } NS_IMETHODIMP nsQueryContentEventResult::GetReversed(bool *aReversed) { NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE); - NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT, - NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(mEventMessage == eQuerySelectedText, NS_ERROR_NOT_AVAILABLE); *aReversed = mReversed; return NS_OK; } @@ -76,7 +76,7 @@ NS_IMETHODIMP nsQueryContentEventResult::GetLeft(int32_t *aLeft) { NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE); - NS_ENSURE_TRUE(IsRectEnabled(mEventID), + NS_ENSURE_TRUE(IsRectEnabled(mEventMessage), NS_ERROR_NOT_AVAILABLE); *aLeft = mRect.x; return NS_OK; @@ -86,7 +86,7 @@ NS_IMETHODIMP nsQueryContentEventResult::GetWidth(int32_t *aWidth) { NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE); - NS_ENSURE_TRUE(IsRectEnabled(mEventID), + NS_ENSURE_TRUE(IsRectEnabled(mEventMessage), NS_ERROR_NOT_AVAILABLE); *aWidth = mRect.width; return NS_OK; @@ -96,7 +96,7 @@ NS_IMETHODIMP nsQueryContentEventResult::GetTop(int32_t *aTop) { NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE); - NS_ENSURE_TRUE(IsRectEnabled(mEventID), + NS_ENSURE_TRUE(IsRectEnabled(mEventMessage), NS_ERROR_NOT_AVAILABLE); *aTop = mRect.y; return NS_OK; @@ -106,7 +106,7 @@ NS_IMETHODIMP nsQueryContentEventResult::GetHeight(int32_t *aHeight) { NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE); - NS_ENSURE_TRUE(IsRectEnabled(mEventID), + NS_ENSURE_TRUE(IsRectEnabled(mEventMessage), NS_ERROR_NOT_AVAILABLE); *aHeight = mRect.height; return NS_OK; @@ -116,8 +116,8 @@ NS_IMETHODIMP nsQueryContentEventResult::GetText(nsAString &aText) { NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE); - NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT || - mEventID == NS_QUERY_TEXT_CONTENT, + NS_ENSURE_TRUE(mEventMessage == eQuerySelectedText || + mEventMessage == eQueryTextContent, NS_ERROR_NOT_AVAILABLE); aText = mString; return NS_OK; @@ -126,7 +126,7 @@ nsQueryContentEventResult::GetText(nsAString &aText) NS_IMETHODIMP nsQueryContentEventResult::GetSucceeded(bool *aSucceeded) { - NS_ENSURE_TRUE(mEventID != 0, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_TRUE(mEventMessage != eVoidEvent, NS_ERROR_NOT_INITIALIZED); *aSucceeded = mSucceeded; return NS_OK; } @@ -135,8 +135,8 @@ NS_IMETHODIMP nsQueryContentEventResult::GetNotFound(bool *aNotFound) { NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE); - NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT || - mEventID == NS_QUERY_CHARACTER_AT_POINT, + NS_ENSURE_TRUE(mEventMessage == eQuerySelectedText || + mEventMessage == NS_QUERY_CHARACTER_AT_POINT, NS_ERROR_NOT_AVAILABLE); *aNotFound = (mOffset == WidgetQueryContentEvent::NOT_FOUND); return NS_OK; @@ -148,7 +148,7 @@ nsQueryContentEventResult::GetTentativeCaretOffsetNotFound(bool* aNotFound) if (NS_WARN_IF(!mSucceeded)) { return NS_ERROR_NOT_AVAILABLE; } - if (NS_WARN_IF(mEventID != NS_QUERY_CHARACTER_AT_POINT)) { + if (NS_WARN_IF(mEventMessage != NS_QUERY_CHARACTER_AT_POINT)) { return NS_ERROR_NOT_AVAILABLE; } *aNotFound = (mTentativeCaretOffset == WidgetQueryContentEvent::NOT_FOUND); @@ -159,7 +159,7 @@ void nsQueryContentEventResult::SetEventResult(nsIWidget* aWidget, const WidgetQueryContentEvent &aEvent) { - mEventID = aEvent.mMessage; + mEventMessage = aEvent.mMessage; mSucceeded = aEvent.mSucceeded; mReversed = aEvent.mReply.mReversed; mRect = aEvent.mReply.mRect; @@ -167,7 +167,7 @@ nsQueryContentEventResult::SetEventResult(nsIWidget* aWidget, mTentativeCaretOffset = aEvent.mReply.mTentativeCaretOffset; mString = aEvent.mReply.mString; - if (!IsRectEnabled(mEventID) || !aWidget || !mSucceeded) { + if (!IsRectEnabled(mEventMessage) || !aWidget || !mSucceeded) { return; } diff --git a/dom/base/nsQueryContentEventResult.h b/dom/base/nsQueryContentEventResult.h index f502456c26..2f9fa4550d 100644 --- a/dom/base/nsQueryContentEventResult.h +++ b/dom/base/nsQueryContentEventResult.h @@ -29,7 +29,7 @@ public: protected: ~nsQueryContentEventResult(); - uint32_t mEventID; + mozilla::EventMessage mEventMessage; uint32_t mOffset; uint32_t mTentativeCaretOffset; diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp index 88e84ea00e..37e2ae35a0 100644 --- a/dom/events/ContentEventHandler.cpp +++ b/dom/events/ContentEventHandler.cpp @@ -796,11 +796,11 @@ nsresult ContentEventHandler::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent) { switch (aEvent->mMessage) { - case NS_QUERY_SELECTED_TEXT: + case eQuerySelectedText: return OnQuerySelectedText(aEvent); - case NS_QUERY_TEXT_CONTENT: + case eQueryTextContent: return OnQueryTextContent(aEvent); - case NS_QUERY_CARET_RECT: + case eQueryCaretRect: return OnQueryCaretRect(aEvent); case NS_QUERY_TEXT_RECT: return OnQueryTextRect(aEvent); @@ -808,7 +808,7 @@ ContentEventHandler::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent) return OnQueryEditorRect(aEvent); case NS_QUERY_CONTENT_STATE: return OnQueryContentState(aEvent); - case NS_QUERY_SELECTION_AS_TRANSFERABLE: + case eQuerySelectionAsTransferable: return OnQuerySelectionAsTransferable(aEvent); case NS_QUERY_CHARACTER_AT_POINT: return OnQueryCharacterAtPoint(aEvent); diff --git a/dom/events/ContentEventHandler.h b/dom/events/ContentEventHandler.h index 34e46f0936..2d16a089d0 100644 --- a/dom/events/ContentEventHandler.h +++ b/dom/events/ContentEventHandler.h @@ -42,11 +42,11 @@ public: // Handle aEvent in the current process. nsresult HandleQueryContentEvent(WidgetQueryContentEvent* aEvent); - // NS_QUERY_SELECTED_TEXT event handler + // eQuerySelectedText event handler nsresult OnQuerySelectedText(WidgetQueryContentEvent* aEvent); - // NS_QUERY_TEXT_CONTENT event handler + // eQueryTextContent event handler nsresult OnQueryTextContent(WidgetQueryContentEvent* aEvent); - // NS_QUERY_CARET_RECT event handler + // eQueryCaretRect event handler nsresult OnQueryCaretRect(WidgetQueryContentEvent* aEvent); // NS_QUERY_TEXT_RECT event handler nsresult OnQueryTextRect(WidgetQueryContentEvent* aEvent); @@ -54,7 +54,7 @@ public: nsresult OnQueryEditorRect(WidgetQueryContentEvent* aEvent); // NS_QUERY_CONTENT_STATE event handler nsresult OnQueryContentState(WidgetQueryContentEvent* aEvent); - // NS_QUERY_SELECTION_AS_TRANSFERABLE event handler + // eQuerySelectionAsTransferable event handler nsresult OnQuerySelectionAsTransferable(WidgetQueryContentEvent* aEvent); // NS_QUERY_CHARACTER_AT_POINT event handler nsresult OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent); diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 4a943e2c19..de455abb21 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -649,11 +649,11 @@ NON_IDL_EVENT(DOMFocusOut, eUIEventClass) NON_IDL_EVENT(DOMMouseScroll, - NS_MOUSE_SCROLL, + eLegacyMouseLineOrPageScroll, EventNameType_HTMLXUL, eMouseScrollEventClass) NON_IDL_EVENT(MozMousePixelScroll, - NS_MOUSE_PIXEL_SCROLL, + eLegacyMousePixelScroll, EventNameType_HTMLXUL, eMouseScrollEventClass) diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index ce36606cbc..7c7b12ee89 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -759,7 +759,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, InitLineOrPageDelta(aTargetFrame, this, wheelEvent); } break; - case NS_SELECTION_SET: + case eSetSelection: IMEStateManager::HandleSelectionEvent(aPresContext, GetFocusedContent(), aEvent->AsSelectionEvent()); break; @@ -784,7 +784,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, // If the event is trusted event, set the selected text to data of // composition event. WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent(); - WidgetQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT, + WidgetQueryContentEvent selectedText(true, eQuerySelectedText, compositionEvent->widget); HandleQueryContentEvent(&selectedText); NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text"); @@ -801,9 +801,9 @@ void EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent) { switch (aEvent->mMessage) { - case NS_QUERY_SELECTED_TEXT: - case NS_QUERY_TEXT_CONTENT: - case NS_QUERY_CARET_RECT: + case eQuerySelectedText: + case eQueryTextContent: + case eQueryCaretRect: case NS_QUERY_TEXT_RECT: case NS_QUERY_EDITOR_RECT: if (!IsTargetCrossProcess(aEvent)) { @@ -814,7 +814,7 @@ EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent) return; // Following events have not been supported in e10s mode yet. case NS_QUERY_CONTENT_STATE: - case NS_QUERY_SELECTION_AS_TRANSFERABLE: + case eQuerySelectionAsTransferable: case NS_QUERY_CHARACTER_AT_POINT: case NS_QUERY_DOM_WIDGET_HITTEST: break; @@ -2209,8 +2209,8 @@ EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame, targetContent = targetContent->GetParent(); } - WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_SCROLL, - aEvent->widget); + WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, + eLegacyMouseLineOrPageScroll, aEvent->widget); event.mFlags.mDefaultPrevented = aState.mDefaultPrevented; event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent; event.refPoint = aEvent->refPoint; @@ -2249,8 +2249,8 @@ EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame, targetContent = targetContent->GetParent(); } - WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_PIXEL_SCROLL, - aEvent->widget); + WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, + eLegacyMousePixelScroll, aEvent->widget); event.mFlags.mDefaultPrevented = aState.mDefaultPrevented; event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent; event.refPoint = aEvent->refPoint; @@ -3101,8 +3101,8 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, break; } case WheelPrefs::ACTION_HISTORY: { - // If this event doesn't cause NS_MOUSE_SCROLL event or the direction - // is oblique, don't perform history back/forward. + // If this event doesn't cause eLegacyMouseLineOrPageScroll event or + // the direction is oblique, don't perform history back/forward. int32_t intDelta = wheelEvent->GetPreferredIntDelta(); if (!intDelta) { break; @@ -3111,8 +3111,8 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, break; } case WheelPrefs::ACTION_ZOOM: { - // If this event doesn't cause NS_MOUSE_SCROLL event or the direction - // is oblique, don't perform zoom in/out. + // If this event doesn't cause eLegacyMouseLineOrPageScroll event or + // the direction is oblique, don't perform zoom in/out. int32_t intDelta = wheelEvent->GetPreferredIntDelta(); if (!intDelta) { break; diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h index bc9fa63edc..5eedf7dc49 100644 --- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -109,8 +109,8 @@ public: nsEventStatus* aStatus); /** - * DispatchLegacyMouseScrollEvents() dispatches NS_MOUSE_SCROLL event and - * NS_MOUSE_PIXEL_SCROLL event for compatiblity with old Gecko. + * DispatchLegacyMouseScrollEvents() dispatches eLegacyMouseLineOrPageScroll + * event and eLegacyMousePixelScroll event for compatibility with old Gecko. */ void DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent, diff --git a/dom/events/IMEContentObserver.cpp b/dom/events/IMEContentObserver.cpp index f5a2479d00..20ecd6f524 100644 --- a/dom/events/IMEContentObserver.cpp +++ b/dom/events/IMEContentObserver.cpp @@ -51,20 +51,20 @@ static const char* ToChar(EventMessage aEventMessage) { switch (aEventMessage) { - case NS_QUERY_SELECTED_TEXT: - return "NS_QUERY_SELECTED_TEXT"; - case NS_QUERY_TEXT_CONTENT: - return "NS_QUERY_TEXT_CONTENT"; - case NS_QUERY_CARET_RECT: - return "NS_QUERY_CARET_RECT"; + case eQuerySelectedText: + return "eQuerySelectedText"; + case eQueryTextContent: + return "eQueryTextContent"; + case eQueryCaretRect: + return "eQueryCaretRect"; case NS_QUERY_TEXT_RECT: return "NS_QUERY_TEXT_RECT"; case NS_QUERY_EDITOR_RECT: return "NS_QUERY_EDITOR_RECT"; case NS_QUERY_CONTENT_STATE: return "NS_QUERY_CONTENT_STATE"; - case NS_QUERY_SELECTION_AS_TRANSFERABLE: - return "NS_QUERY_SELECTION_AS_TRANSFERABLE"; + case eQuerySelectionAsTransferable: + return "eQuerySelectionAsTransferable"; case NS_QUERY_CHARACTER_AT_POINT: return "NS_QUERY_CHARACTER_AT_POINT"; case NS_QUERY_DOM_WIDGET_HITTEST: @@ -569,8 +569,7 @@ IMEContentObserver::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent) // If the instance has cache, it should use the cached selection which was // sent to the widget. - if (aEvent->mMessage == NS_QUERY_SELECTED_TEXT && - aEvent->mUseNativeLineBreak && + if (aEvent->mMessage == eQuerySelectedText && aEvent->mUseNativeLineBreak && mSelectionData.IsValid()) { aEvent->mReply.mContentsRoot = mRootContent; aEvent->mReply.mHasSelection = !mSelectionData.IsCollapsed(); @@ -1109,7 +1108,7 @@ IMEContentObserver::UpdateSelectionCache() // XXX Cannot we cache some information for reducing the cost to compute // selection offset and writing mode? - WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, mWidget); + WidgetQueryContentEvent selection(true, eQuerySelectedText, mWidget); ContentEventHandler handler(GetPresContext()); handler.OnQuerySelectedText(&selection); if (NS_WARN_IF(!selection.mSucceeded)) { diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 253da56a8e..d9231f6d11 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -149,8 +149,8 @@ GetEventMessageName(EventMessage aMessage) return "NS_COMPOSITION_COMMIT_AS_IS"; case NS_COMPOSITION_COMMIT: return "NS_COMPOSITION_COMMIT"; - case NS_SELECTION_SET: - return "NS_SELECTION_SET"; + case eSetSelection: + return "eSetSelection"; default: return "unacceptable event message"; } diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 19946b980f..79458fd5e5 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -415,9 +415,7 @@ TextComposition::NotityUpdateComposition( if (aCompositionEvent->mMessage == NS_COMPOSITION_START) { nsCOMPtr widget = mPresContext->GetRootWidget(); // Update composition start offset - WidgetQueryContentEvent selectedTextEvent(true, - NS_QUERY_SELECTED_TEXT, - widget); + WidgetQueryContentEvent selectedTextEvent(true, eQuerySelectedText, widget); widget->DispatchEvent(&selectedTextEvent, status); if (selectedTextEvent.mSucceeded) { mCompositionStartOffset = selectedTextEvent.mReply.mOffset; @@ -615,8 +613,7 @@ TextComposition::CompositionEventDispatcher::Run() switch (mEventMessage) { case NS_COMPOSITION_START: { WidgetCompositionEvent compStart(true, NS_COMPOSITION_START, widget); - WidgetQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT, - widget); + WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget); ContentEventHandler handler(presContext); handler.OnQuerySelectedText(&selectedText); NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text"); diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index ea930d9750..5e7d8a1165 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -2458,8 +2458,8 @@ nsGenericHTMLFormElement::IsElementDisabledForEvents(EventMessage aMessage, case ePointerEnter: case ePointerLeave: case NS_WHEEL_WHEEL: - case NS_MOUSE_SCROLL: - case NS_MOUSE_PIXEL_SCROLL: + case eLegacyMouseLineOrPageScroll: + case eLegacyMousePixelScroll: return false; default: break; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 23f784cb76..0ed12e5745 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2334,7 +2334,7 @@ TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) } switch (aEvent.mMessage) { case NS_QUERY_TEXT_RECT: - case NS_QUERY_CARET_RECT: + case eQueryCaretRect: case NS_QUERY_EDITOR_RECT: aEvent.mReply.mRect -= GetChildProcessOffset(); break; diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 503e454b7e..c5c0540f0b 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -1812,7 +1812,7 @@ CocoaEventTypeForEvent(const WidgetGUIEvent& anEvent, nsIFrame* aObjectFrame) case eFocus: case eBlur: return NPCocoaEventFocusChanged; - case NS_MOUSE_SCROLL: + case eLegacyMouseLineOrPageScroll: return NPCocoaEventScrollWheel; default: return (NPCocoaEventType)0; @@ -1829,7 +1829,7 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame) if (anEvent->mMessage == eMouseMove || anEvent->mMessage == eMouseDown || anEvent->mMessage == eMouseUp || - anEvent->mMessage == NS_MOUSE_SCROLL || + anEvent->mMessage == eLegacyMouseLineOrPageScroll || anEvent->mMessage == eMouseOver || anEvent->mMessage == eMouseOut) { @@ -1871,14 +1871,14 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame) } break; } - case NS_MOUSE_SCROLL: - { + case eLegacyMouseLineOrPageScroll: { WidgetWheelEvent* wheelEvent = anEvent->AsWheelEvent(); if (wheelEvent) { cocoaEvent.data.mouse.deltaX = wheelEvent->lineOrPageDeltaX; cocoaEvent.data.mouse.deltaY = wheelEvent->lineOrPageDeltaY; } else { - NS_WARNING("NS_MOUSE_SCROLL is not a WidgetWheelEvent? (could be, haven't checked)"); + NS_WARNING("eLegacyMouseLineOrPageScroll is not a WidgetWheelEvent? " + "(could be, haven't checked)"); } break; } diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index b16f1746a8..02d7ab48b8 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -2081,8 +2081,8 @@ gfxFont::IsSpaceGlyphInvisible(gfxContext *aRefContext, gfxTextRun *aTextRun) GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit()); gfxRect glyphExtents; mFontEntry->mSpaceGlyphIsInvisible = - extents->GetTightGlyphExtentsAppUnits(this, eHorizontal, - aRefContext, GetSpaceGlyph(), &glyphExtents) && + extents->GetTightGlyphExtentsAppUnits(this, aRefContext, + GetSpaceGlyph(), &glyphExtents) && glyphExtents.IsEmpty(); mFontEntry->mSpaceGlyphIsInvisibleInitialized = true; } @@ -2189,11 +2189,14 @@ gfxFont::Measure(gfxTextRun *aTextRun, } else { gfxRect glyphRect; if (!extents->GetTightGlyphExtentsAppUnits(this, - orientation, aRefContext, glyphIndex, &glyphRect)) { glyphRect = gfxRect(0, metrics.mBoundingBox.Y(), advance, metrics.mBoundingBox.Height()); } + if (orientation == eVertical) { + Swap(glyphRect.x, glyphRect.y); + Swap(glyphRect.width, glyphRect.height); + } if (isRTL) { glyphRect -= gfxPoint(advance, 0); } @@ -2218,13 +2221,16 @@ gfxFont::Measure(gfxTextRun *aTextRun, gfxRect glyphRect; if (glyphData->IsMissing() || !extents || !extents->GetTightGlyphExtentsAppUnits(this, - orientation, aRefContext, glyphIndex, &glyphRect)) { // We might have failed to get glyph extents due to // OOM or something glyphRect = gfxRect(0, -metrics.mAscent, advance, metrics.mAscent + metrics.mDescent); } + if (orientation == eVertical) { + Swap(glyphRect.x, glyphRect.y); + Swap(glyphRect.width, glyphRect.height); + } if (isRTL) { glyphRect -= gfxPoint(advance, 0); } @@ -3108,7 +3114,7 @@ gfxFont::GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit) { } void -gfxFont::SetupGlyphExtents(gfxContext *aContext, Orientation aOrientation, +gfxFont::SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID, bool aNeedTight, gfxGlyphExtents *aExtents) { @@ -3134,7 +3140,7 @@ gfxFont::SetupGlyphExtents(gfxContext *aContext, Orientation aOrientation, cairo_text_extents_t extents; cairo_glyph_extents(aContext->GetCairo(), &glyph, 1, &extents); - const Metrics& fontMetrics = GetMetrics(aOrientation); + const Metrics& fontMetrics = GetMetrics(eHorizontal); int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit(); if (!aNeedTight && extents.x_bearing >= 0 && extents.y_bearing >= -fontMetrics.maxAscent && diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 084645b274..3145436bf6 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -1614,8 +1614,7 @@ public: gfxGlyphExtents *GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit); // You need to call SetupCairoFont on the aCR just before calling this - virtual void SetupGlyphExtents(gfxContext *aContext, - Orientation aOrientation, uint32_t aGlyphID, + virtual void SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID, bool aNeedTight, gfxGlyphExtents *aExtents); // This is called by the default Draw() implementation above. diff --git a/gfx/thebes/gfxGlyphExtents.cpp b/gfx/thebes/gfxGlyphExtents.cpp index 16e66353ee..ce5440e499 100644 --- a/gfx/thebes/gfxGlyphExtents.cpp +++ b/gfx/thebes/gfxGlyphExtents.cpp @@ -36,7 +36,6 @@ gfxGlyphExtents::~gfxGlyphExtents() bool gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont, - gfxFont::Orientation aOrientation, gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents) { HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID); @@ -50,8 +49,7 @@ gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont, #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS ++gGlyphExtentsSetupLazyTight; #endif - aFont->SetupGlyphExtents(aContext, aOrientation, aGlyphID, true, - this); + aFont->SetupGlyphExtents(aContext, aGlyphID, true, this); entry = mTightGlyphExtents.GetEntry(aGlyphID); } if (!entry) { diff --git a/gfx/thebes/gfxGlyphExtents.h b/gfx/thebes/gfxGlyphExtents.h index cda58a4b8f..14cd57fa59 100644 --- a/gfx/thebes/gfxGlyphExtents.h +++ b/gfx/thebes/gfxGlyphExtents.h @@ -63,7 +63,6 @@ public: // Returns true on success. Can fail on OOM or when aContext is null // and extents were not (successfully) prefetched. bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, - gfxFont::Orientation aOrientation, gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents); void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) { diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 8782e8bdde..fb63dcd7a1 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1374,8 +1374,6 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext) for (j = start; j < end; ++j) { const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j]; - gfxFont::Orientation orientation = - IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal; if (glyphData->IsSimpleGlyph()) { // If we're in speed mode, don't set up glyph extents here; we'll // just return "optimistic" glyph bounds later @@ -1392,7 +1390,7 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext) #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS ++gGlyphExtentsSetupEagerSimple; #endif - font->SetupGlyphExtents(aRefContext, orientation, + font->SetupGlyphExtents(aRefContext, glyphIndex, false, extents); } } @@ -1418,7 +1416,7 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext) #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS ++gGlyphExtentsSetupEagerTight; #endif - font->SetupGlyphExtents(aRefContext, orientation, + font->SetupGlyphExtents(aRefContext, glyphIndex, true, extents); } } diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 126b445895..e074b04b1f 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -7164,7 +7164,7 @@ PresShell::HandleEvent(nsIFrame* aFrame, if (presShell != this) { nsIFrame* frame = presShell->GetRootFrame(); if (!frame) { - if (aEvent->mMessage == NS_QUERY_TEXT_CONTENT || + if (aEvent->mMessage == eQueryTextContent || aEvent->IsContentCommandEvent()) { return NS_OK; } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index c71b98787c..11e0b84525 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -3019,6 +3019,7 @@ nsFrame::HandlePress(nsPresContext* aPresContext, if (curDetail->mType != nsISelectionController::SELECTION_SPELLCHECK && curDetail->mType != nsISelectionController::SELECTION_FIND && curDetail->mType != nsISelectionController::SELECTION_URLSECONDARY && + curDetail->mType != nsISelectionController::SELECTION_URLSTRIKEOUT && curDetail->mStart <= offsets.StartOffset() && offsets.EndOffset() <= curDetail->mEnd) { diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index db0baea794..ade505d89a 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -3285,7 +3285,7 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflo if (pfd->mRecomputeOverflow || frame->StyleContext()->HasTextDecorationLines()) { nsTextFrame* f = static_cast(frame); - r = f->RecomputeOverflow(*mBlockReflowState); + r = f->RecomputeOverflow(mBlockReflowState->frame); } frame->FinishAndStoreOverflow(r, frame->GetSize()); } diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index f5bbb91fb2..90f816ffb3 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -275,6 +275,7 @@ GetIndexFromSelectionType(SelectionType aType) case nsISelectionController::SELECTION_ACCESSIBILITY: return 6; break; case nsISelectionController::SELECTION_FIND: return 7; break; case nsISelectionController::SELECTION_URLSECONDARY: return 8; break; + case nsISelectionController::SELECTION_URLSTRIKEOUT: return 9; break; default: return -1; break; } @@ -296,6 +297,7 @@ GetSelectionTypeFromIndex(int8_t aIndex) case 6: return nsISelectionController::SELECTION_ACCESSIBILITY; break; case 7: return nsISelectionController::SELECTION_FIND; break; case 8: return nsISelectionController::SELECTION_URLSECONDARY; break; + case 9: return nsISelectionController::SELECTION_URLSTRIKEOUT; break; default: return nsISelectionController::SELECTION_NORMAL; break; } diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index fdf186ed08..15cf241445 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -354,6 +354,9 @@ public: } } + nscolor GetSystemFieldForegroundColor(); + nscolor GetSystemFieldBackgroundColor(); + protected: nsTextFrame* mFrame; nsPresContext* mPresContext; @@ -373,6 +376,8 @@ protected: int32_t mSufficientContrast; nscolor mFrameBackgroundColor; + nscolor mSystemFieldForegroundColor; + nscolor mSystemFieldBackgroundColor; // selection colors and underline info, the colors are resolved colors if // mResolveColors is true (which is the default), i.e., the foreground color @@ -3637,6 +3642,11 @@ nsTextPaintStyle::InitCommonColors() nscolor defaultBgColor = mPresContext->DefaultBackgroundColor(); mFrameBackgroundColor = NS_ComposeColors(defaultBgColor, bgColor); + mSystemFieldForegroundColor = + LookAndFeel::GetColor(LookAndFeel::eColorID__moz_fieldtext); + mSystemFieldBackgroundColor = + LookAndFeel::GetColor(LookAndFeel::eColorID__moz_field); + if (bgFrame->IsThemed()) { // Assume a native widget has sufficient contrast always mSufficientContrast = 0; @@ -3664,6 +3674,20 @@ nsTextPaintStyle::InitCommonColors() mInitCommonColors = true; } +nscolor +nsTextPaintStyle::GetSystemFieldForegroundColor() +{ + InitCommonColors(); + return mSystemFieldForegroundColor; +} + +nscolor +nsTextPaintStyle::GetSystemFieldBackgroundColor() +{ + InitCommonColors(); + return mSystemFieldBackgroundColor; +} + static Element* FindElementAncestorForMozSelection(nsIContent* aContent) { @@ -4830,6 +4854,18 @@ LazyGetLineBaselineOffset(nsIFrame* aChildFrame, nsBlockFrame* aBlockFrame) } } +static bool IsUnderlineRight(nsIFrame* aFrame) +{ + nsIAtom* langAtom = aFrame->StyleFont()->mLanguage; + if (!langAtom) { + return false; + } + nsAtomString langStr(langAtom); + return (StringBeginsWith(langStr, NS_LITERAL_STRING("ja")) || + StringBeginsWith(langStr, NS_LITERAL_STRING("ko"))) && + (langStr.Length() == 2 || langStr[2] == '-'); +} + void nsTextFrame::GetTextDecorations( nsPresContext* aPresContext, @@ -4928,11 +4964,19 @@ nsTextFrame::GetTextDecorations( color = nsLayoutUtils::GetColor(f, eCSSProperty_text_decoration_color); } - if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE) { + bool swapUnderlineAndOverline = vertical && IsUnderlineRight(f); + const uint8_t kUnderline = + swapUnderlineAndOverline ? NS_STYLE_TEXT_DECORATION_LINE_OVERLINE : + NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE; + const uint8_t kOverline = + swapUnderlineAndOverline ? NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE : + NS_STYLE_TEXT_DECORATION_LINE_OVERLINE; + + if (textDecorations & kUnderline) { aDecorations.mUnderlines.AppendElement( nsTextFrame::LineDecoration(f, baselineOffset, color, style)); } - if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_OVERLINE) { + if (textDecorations & kOverline) { aDecorations.mOverlines.AppendElement( nsTextFrame::LineDecoration(f, baselineOffset, color, style)); } @@ -4965,6 +5009,12 @@ nsTextFrame::GetTextDecorations( if (f->IsFloating() || f->IsAbsolutelyPositioned()) { break; } + + // If we're an outer element, which is classified as an atomic + // inline-level element, we're done. + if (f->GetType() == nsGkAtoms::svgOuterSVGFrame) { + break; + } } } @@ -5175,16 +5225,16 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext, AddStateBits(TEXT_SELECTION_UNDERLINE_OVERFLOWED); } -static gfxFloat -ComputeDescentLimitForSelectionUnderline(nsPresContext* aPresContext, - nsTextFrame* aFrame, - const gfxFont::Metrics& aFontMetrics) +gfxFloat +nsTextFrame::ComputeDescentLimitForSelectionUnderline( + nsPresContext* aPresContext, + const gfxFont::Metrics& aFontMetrics) { gfxFloat app = aPresContext->AppUnitsPerDevPixel(); nscoord lineHeightApp = - nsHTMLReflowState::CalcLineHeight(aFrame->GetContent(), - aFrame->StyleContext(), NS_AUTOHEIGHT, - aFrame->GetFontSizeInflation()); + nsHTMLReflowState::CalcLineHeight(GetContent(), + StyleContext(), NS_AUTOHEIGHT, + GetFontSizeInflation()); gfxFloat lineHeight = gfxFloat(lineHeightApp) / app; if (lineHeight <= aFontMetrics.maxHeight) { return aFontMetrics.maxDescent; @@ -5196,15 +5246,18 @@ ComputeDescentLimitForSelectionUnderline(nsPresContext* aPresContext, // Make sure this stays in sync with DrawSelectionDecorations below static const SelectionType SelectionTypesWithDecorations = nsISelectionController::SELECTION_SPELLCHECK | + nsISelectionController::SELECTION_URLSTRIKEOUT | nsISelectionController::SELECTION_IME_RAWINPUT | nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT | nsISelectionController::SELECTION_IME_CONVERTEDTEXT | nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT; -static gfxFloat -ComputeSelectionUnderlineHeight(nsPresContext* aPresContext, - const gfxFont::Metrics& aFontMetrics, - SelectionType aSelectionType) +/* static */ +gfxFloat +nsTextFrame::ComputeSelectionUnderlineHeight( + nsPresContext* aPresContext, + const gfxFont::Metrics& aFontMetrics, + SelectionType aSelectionType) { switch (aSelectionType) { case nsISelectionController::SELECTION_IME_RAWINPUT: @@ -5232,28 +5285,22 @@ ComputeSelectionUnderlineHeight(nsPresContext* aPresContext, } } -enum DecorationType { - eNormalDecoration, - eSelectionDecoration -}; - -static void -PaintDecorationLine(nsIFrame* aFrame, - gfxContext* const aCtx, - const gfxRect& aDirtyRect, - nscolor aColor, - const nscolor* aOverrideColor, - const gfxPoint& aPt, - gfxFloat aICoordInFrame, - const gfxSize& aLineSize, - gfxFloat aAscent, - gfxFloat aOffset, - uint8_t aDecoration, - uint8_t aStyle, - DecorationType aDecorationType, - nsTextFrame::DrawPathCallbacks* aCallbacks, - bool aVertical, - gfxFloat aDescentLimit = -1.0) +void +nsTextFrame::PaintDecorationLine(gfxContext* const aCtx, + const gfxRect& aDirtyRect, + nscolor aColor, + const nscolor* aOverrideColor, + const gfxPoint& aPt, + gfxFloat aICoordInFrame, + const gfxSize& aLineSize, + gfxFloat aAscent, + gfxFloat aOffset, + uint8_t aDecoration, + uint8_t aStyle, + DecorationType aDecorationType, + DrawPathCallbacks* aCallbacks, + bool aVertical, + gfxFloat aDescentLimit /* = -1.0 */) { nscolor lineColor = aOverrideColor ? *aOverrideColor : aColor; if (aCallbacks) { @@ -5262,7 +5309,7 @@ PaintDecorationLine(nsIFrame* aFrame, } else { aCallbacks->NotifyBeforeSelectionDecorationLine(lineColor); } - nsCSSRendering::DecorationLineToPath(aFrame, aCtx, aDirtyRect, lineColor, + nsCSSRendering::DecorationLineToPath(this, aCtx, aDirtyRect, lineColor, aPt, aICoordInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle, aVertical, aDescentLimit); if (aDecorationType == eNormalDecoration) { @@ -5271,7 +5318,7 @@ PaintDecorationLine(nsIFrame* aFrame, aCallbacks->NotifySelectionDecorationLinePathEmitted(); } } else { - nsCSSRendering::PaintDecorationLine(aFrame, *aCtx->GetDrawTarget(), + nsCSSRendering::PaintDecorationLine(this, *aCtx->GetDrawTarget(), ToRect(aDirtyRect), lineColor, aPt, Float(aICoordInFrame), aLineSize, aAscent, aOffset, aDecoration, aStyle, aVertical, aDescentLimit); @@ -5282,16 +5329,20 @@ PaintDecorationLine(nsIFrame* aFrame, * This, plus SelectionTypesWithDecorations, encapsulates all knowledge about * drawing text decoration for selections. */ -static void DrawSelectionDecorations(gfxContext* aContext, - const gfxRect& aDirtyRect, - SelectionType aType, - nsTextFrame* aFrame, - nsTextPaintStyle& aTextPaintStyle, - const TextRangeStyle &aRangeStyle, - const gfxPoint& aPt, gfxFloat aICoordInFrame, gfxFloat aWidth, - gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics, - nsTextFrame::DrawPathCallbacks* aCallbacks, - bool aVertical) +void +nsTextFrame::DrawSelectionDecorations(gfxContext* aContext, + const gfxRect& aDirtyRect, + SelectionType aType, + nsTextPaintStyle& aTextPaintStyle, + const TextRangeStyle &aRangeStyle, + const gfxPoint& aPt, + gfxFloat aICoordInFrame, + gfxFloat aWidth, + gfxFloat aAscent, + const gfxFont::Metrics& aFontMetrics, + DrawPathCallbacks* aCallbacks, + bool aVertical, + uint8_t aDecoration) { gfxPoint pt(aPt); gfxSize size(aWidth, @@ -5299,7 +5350,7 @@ static void DrawSelectionDecorations(gfxContext* aContext, aFontMetrics, aType)); gfxFloat descentLimit = ComputeDescentLimitForSelectionUnderline(aTextPaintStyle.PresContext(), - aFrame, aFontMetrics); + aFontMetrics); float relativeSize; uint8_t style; @@ -5310,6 +5361,9 @@ static void DrawSelectionDecorations(gfxContext* aContext, aTextPaintStyle.GetSelectionUnderlineForPaint(index, &color, &relativeSize, &style); + gfxFloat offset = aDecoration == NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE ? + aFontMetrics.underlineOffset : aFontMetrics.maxAscent; + switch (aType) { case nsISelectionController::SELECTION_IME_RAWINPUT: case nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT: @@ -5342,13 +5396,25 @@ static void DrawSelectionDecorations(gfxContext* aContext, // There is no underline style definition. return; } - if (aRangeStyle.IsUnderlineColorDefined()) { + // If underline color is defined and that doesn't depend on the + // foreground color, we should use the color directly. + if (aRangeStyle.IsUnderlineColorDefined() && + aRangeStyle.IsForegroundColorDefined() && + aRangeStyle.mUnderlineColor != aRangeStyle.mForegroundColor) { color = aRangeStyle.mUnderlineColor; - } else if (aRangeStyle.IsForegroundColorDefined()) { - color = aRangeStyle.mForegroundColor; - } else { - NS_ASSERTION(!aRangeStyle.IsBackgroundColorDefined(), - "Only the background color is defined"); + } + // If foreground color or background color is defined, the both colors + // are computed by GetSelectionTextColors(). Then, we should use its + // foreground color always. The color should have sufficient contrast + // with the background color. + else if (aRangeStyle.IsForegroundColorDefined() || + aRangeStyle.IsBackgroundColorDefined()) { + nscolor bg; + GetSelectionTextColors(aType, aTextPaintStyle, aRangeStyle, + &color, &bg); + } + // Otherwise, use the foreground color of the frame. + else { color = aTextPaintStyle.GetTextColor(); } } else if (!weDefineSelectionUnderline) { @@ -5362,30 +5428,37 @@ static void DrawSelectionDecorations(gfxContext* aContext, if (!weDefineSelectionUnderline) return; break; + case nsISelectionController::SELECTION_URLSTRIKEOUT: { + nscoord inflationMinFontSize = + nsLayoutUtils::InflationMinFontSizeFor(this); + float inflation = + GetInflationForTextDecorations(this, inflationMinFontSize); + const gfxFont::Metrics metrics = + GetFirstFontMetrics(GetFontGroupForFrame(this, inflation), aVertical); + + relativeSize = 2.0f; + offset = metrics.strikeoutOffset + 0.5; + aDecoration = NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH; + break; + } default: NS_WARNING("Requested selection decorations when there aren't any"); return; } size.height *= relativeSize; - PaintDecorationLine(aFrame, aContext, aDirtyRect, color, nullptr, pt, + PaintDecorationLine(aContext, aDirtyRect, color, nullptr, pt, (aVertical ? (pt.y - aPt.y) : (pt.x - aPt.x)) + aICoordInFrame, - size, aAscent, aFontMetrics.underlineOffset, - NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, style, eSelectionDecoration, + size, aAscent, offset, aDecoration, style, eSelectionDecoration, aCallbacks, aVertical, descentLimit); } -/** - * This function encapsulates all knowledge of how selections affect foreground - * and background colors. - * @return true if the selection affects colors, false otherwise - * @param aForeground the foreground color to use - * @param aBackground the background color to use, or RGBA(0,0,0,0) if no - * background should be painted - */ -static bool GetSelectionTextColors(SelectionType aType, - nsTextPaintStyle& aTextPaintStyle, - const TextRangeStyle &aRangeStyle, - nscolor* aForeground, nscolor* aBackground) +/* static */ +bool +nsTextFrame::GetSelectionTextColors(SelectionType aType, + nsTextPaintStyle& aTextPaintStyle, + const TextRangeStyle &aRangeStyle, + nscolor* aForeground, + nscolor* aBackground) { switch (aType) { case nsISelectionController::SELECTION_NORMAL: @@ -5402,17 +5475,28 @@ static bool GetSelectionTextColors(SelectionType aType, case nsISelectionController::SELECTION_IME_CONVERTEDTEXT: case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT: if (aRangeStyle.IsDefined()) { - *aForeground = aTextPaintStyle.GetTextColor(); - *aBackground = NS_RGBA(0,0,0,0); if (!aRangeStyle.IsForegroundColorDefined() && !aRangeStyle.IsBackgroundColorDefined()) { + *aForeground = aTextPaintStyle.GetTextColor(); + *aBackground = NS_RGBA(0,0,0,0); return false; } if (aRangeStyle.IsForegroundColorDefined()) { *aForeground = aRangeStyle.mForegroundColor; - } - if (aRangeStyle.IsBackgroundColorDefined()) { + if (aRangeStyle.IsBackgroundColorDefined()) { + *aBackground = aRangeStyle.mBackgroundColor; + } else { + // If foreground color is defined but background color isn't + // defined, we can guess that IME must expect that the background + // color is system's default field background color. + *aBackground = aTextPaintStyle.GetSystemFieldBackgroundColor(); + } + } else { // aRangeStyle.IsBackgroundColorDefined() is true *aBackground = aRangeStyle.mBackgroundColor; + // If background color is defined but foreground color isn't defined, + // we can assume that IME must expect that the foreground color is + // same as system's field text color. + *aForeground = aTextPaintStyle.GetSystemFieldForegroundColor(); } return true; } @@ -5568,6 +5652,9 @@ AddHyphenToMetrics(nsTextFrame* aTextFrame, gfxTextRun* aBaseTextRun, gfxTextRun::Metrics hyphenMetrics = hyphenTextRun->MeasureText(0, hyphenTextRun->GetLength(), aBoundingBoxType, aContext, nullptr); + if (aTextFrame->GetWritingMode().IsLineInverted()) { + hyphenMetrics.mBoundingBox.y = -hyphenMetrics.mBoundingBox.YMost(); + } aMetrics->CombineWith(hyphenMetrics, aBaseTextRun->IsRightToLeft()); } @@ -5832,6 +5919,10 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx, gfxFont* firstFont = aProvider.GetFontGroup()->GetFirstValidFont(); bool verticalRun = mTextRun->IsVertical(); + bool rightUnderline = verticalRun && IsUnderlineRight(this); + const uint8_t kDecoration = + rightUnderline ? NS_STYLE_TEXT_DECORATION_LINE_OVERLINE : + NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE; bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline(); gfxFont::Metrics decorationMetrics(firstFont->GetMetrics(useVerticalMetrics ? @@ -5875,10 +5966,10 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx, } gfxFloat width = Abs(advance) / app; gfxFloat xInFrame = pt.x - (aFramePt.x / app); - DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, this, + DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, aTextPaintStyle, selectedStyle, pt, xInFrame, width, mAscent / app, decorationMetrics, - aCallbacks, verticalRun); + aCallbacks, verticalRun, kDecoration); } iterator.UpdateWithAdvance(advance); } @@ -6388,7 +6479,7 @@ nsTextFrame::DrawTextRunAndDecorations( decSize.height = metrics.underlineSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; - PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor, + PaintDecorationLine(aCtx, dirtyRect, dec.mColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent, metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, dec.mStyle, eNormalDecoration, aCallbacks, verticalRun); @@ -6409,7 +6500,7 @@ nsTextFrame::DrawTextRunAndDecorations( decSize.height = metrics.underlineSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; - PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor, + PaintDecorationLine(aCtx, dirtyRect, dec.mColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent, metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle, eNormalDecoration, aCallbacks, verticalRun); @@ -6436,7 +6527,7 @@ nsTextFrame::DrawTextRunAndDecorations( decSize.height = metrics.strikeoutSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; - PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor, + PaintDecorationLine(aCtx, dirtyRect, dec.mColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent, metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, dec.mStyle, eNormalDecoration, aCallbacks, verticalRun); @@ -6647,7 +6738,7 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext, gfxFloat underlineOffset = fontGroup->GetUnderlineOffset(); gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(mAscent); gfxFloat descentLimit = - ComputeDescentLimitForSelectionUnderline(aPresContext, this, metrics); + ComputeDescentLimitForSelectionUnderline(aPresContext, metrics); SelectionDetails *details = GetSelectionDetails(); for (SelectionDetails *sd = details; sd; sd = sd->mNext) { @@ -7654,8 +7745,9 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext, // XXXldb Shouldn't we be including the newline as part of the // segment that it ends rather than part of the segment that it // starts? - NS_ASSERTION(preformatNewlines, - "We can't be here unless newlines are hard breaks"); + NS_ASSERTION(preformatNewlines || preformatTabs, + "We can't be here unless newlines are " + "hard breaks or there are tabs"); preformattedNewline = preformatNewlines && textRun->CharIsNewline(i); preformattedTab = preformatTabs && textRun->CharIsTab(i); if (!preformattedNewline && !preformattedTab) { @@ -7799,12 +7891,12 @@ nsTextFrame::ComputeTightBounds(gfxContext* aContext) const ComputeTransformedLength(provider), gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, aContext, &provider); + if (GetWritingMode().IsLineInverted()) { + metrics.mBoundingBox.y = -metrics.mBoundingBox.YMost(); + } // mAscent should be the same as metrics.mAscent, but it's what we use to // paint so that's the one we'll use. nsRect boundingBox = RoundOut(metrics.mBoundingBox); - if (GetWritingMode().IsLineInverted()) { - boundingBox.y = -boundingBox.YMost(); - } boundingBox += nsPoint(0, mAscent); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. @@ -8375,7 +8467,8 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, (GetStateBits() & TEXT_IS_IN_TOKEN_MATHML); gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority(); gfxTextRun::SuppressBreak suppressBreak = gfxTextRun::eNoSuppressBreak; - if (ShouldSuppressLineBreak()) { + bool shouldSuppressLineBreak = ShouldSuppressLineBreak(); + if (shouldSuppressLineBreak) { suppressBreak = gfxTextRun::eSuppressAllBreaks; } else if (!aLineLayout.LineIsBreakable()) { suppressBreak = gfxTextRun::eSuppressInitialBreak; @@ -8398,6 +8491,10 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, textMetrics.mDescent = gfxFloat(fm->MaxDescent()); } } + if (GetWritingMode().IsLineInverted()) { + Swap(textMetrics.mAscent, textMetrics.mDescent); + textMetrics.mBoundingBox.y = -textMetrics.mBoundingBox.YMost(); + } // The "end" iterator points to the first character after the string mapped // by this frame. Basically, its original-string offset is offset+charsFit // after we've computed charsFit. @@ -8503,31 +8600,21 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, finalSize.BSize(wm) = 0; } else if (boundingBoxType != gfxFont::LOOSE_INK_EXTENTS) { // Use actual text metrics for floating first letter frame. - if (wm.IsLineInverted()) { - aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mDescent)); - finalSize.BSize(wm) = aMetrics.BlockStartAscent() + - NSToCoordCeil(textMetrics.mAscent); - } else { - aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent)); - finalSize.BSize(wm) = aMetrics.BlockStartAscent() + - NSToCoordCeil(textMetrics.mDescent); - } + aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent)); + finalSize.BSize(wm) = aMetrics.BlockStartAscent() + + NSToCoordCeil(textMetrics.mDescent); } else { // Otherwise, ascent should contain the overline drawable area. // And also descent should contain the underline drawable area. // nsFontMetrics::GetMaxAscent/GetMaxDescent contains them. nsFontMetrics* fm = provider.GetFontMetrics(); - nscoord fontAscent = fm->MaxAscent(); - nscoord fontDescent = fm->MaxDescent(); - if (wm.IsLineInverted()) { - aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent)); - nscoord descent = std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent); - finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent; - } else { - aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent)); - nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent); - finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent; - } + nscoord fontAscent = + wm.IsLineInverted() ? fm->MaxDescent() : fm->MaxAscent(); + nscoord fontDescent = + wm.IsLineInverted() ? fm->MaxAscent() : fm->MaxDescent(); + aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent)); + nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent); + finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent; } aMetrics.SetSize(wm, finalSize); @@ -8541,14 +8628,18 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, // Handle text that runs outside its normal bounds. nsRect boundingBox = RoundOut(textMetrics.mBoundingBox); - if (wm.IsLineInverted()) { - boundingBox.y = -boundingBox.YMost(); - } - boundingBox += nsPoint(0, mAscent); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. Swap(boundingBox.x, boundingBox.y); Swap(boundingBox.width, boundingBox.height); + if (GetWritingMode().IsVerticalRL()) { + boundingBox.x = -boundingBox.XMost(); + boundingBox.x += aMetrics.Width() - mAscent; + } else { + boundingBox.x += mAscent; + } + } else { + boundingBox.y += mAscent; } aMetrics.SetOverflowAreasToDesiredBounds(); aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox); @@ -8572,36 +8663,38 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, aLineLayout.SetTrimmableISize(NSToCoordFloor(trimmableWidth)); AddStateBits(TEXT_HAS_NONCOLLAPSED_CHARACTERS); } - if (charsFit > 0 && charsFit == length && - textStyle->mHyphens != NS_STYLE_HYPHENS_NONE && - HasSoftHyphenBefore(frag, mTextRun, offset, end)) { - bool fits = - textMetrics.mAdvanceWidth + provider.GetHyphenWidth() <= availWidth; - // Record a potential break after final soft hyphen - aLineLayout.NotifyOptionalBreakPosition(this, length, fits, - gfxBreakPriority::eNormalBreak); - } bool breakAfter = forceBreakAfter; - // length == 0 means either the text is empty or it's all collapsed away - bool emptyTextAtStartOfLine = atStartOfLine && length == 0; - if (!breakAfter && charsFit == length && !emptyTextAtStartOfLine && - transformedOffset + transformedLength == mTextRun->GetLength() && - !ShouldSuppressLineBreak() && - (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK)) { - // We placed all the text in the textrun and we have a break opportunity at - // the end of the textrun. We need to record it because the following - // content may not care about nsLineBreaker. - - // Note that because we didn't break, we can be sure that (thanks to the - // code up above) textMetrics.mAdvanceWidth includes the width of any - // trailing whitespace. So we need to subtract trimmableWidth here - // because if we did break at this point, that much width would be trimmed. - if (textMetrics.mAdvanceWidth - trimmableWidth > availWidth) { - breakAfter = true; - } else { - aLineLayout.NotifyOptionalBreakPosition(this, length, true, + if (!shouldSuppressLineBreak) { + if (charsFit > 0 && charsFit == length && + textStyle->mHyphens != NS_STYLE_HYPHENS_NONE && + HasSoftHyphenBefore(frag, mTextRun, offset, end)) { + bool fits = + textMetrics.mAdvanceWidth + provider.GetHyphenWidth() <= availWidth; + // Record a potential break after final soft hyphen + aLineLayout.NotifyOptionalBreakPosition(this, length, fits, gfxBreakPriority::eNormalBreak); } + // length == 0 means either the text is empty or it's all collapsed away + bool emptyTextAtStartOfLine = atStartOfLine && length == 0; + if (!breakAfter && charsFit == length && !emptyTextAtStartOfLine && + transformedOffset + transformedLength == mTextRun->GetLength() && + (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK)) { + // We placed all the text in the textrun and we have a break opportunity + // at the end of the textrun. We need to record it because the following + // content may not care about nsLineBreaker. + + // Note that because we didn't break, we can be sure that (thanks to the + // code up above) textMetrics.mAdvanceWidth includes the width of any + // trailing whitespace. So we need to subtract trimmableWidth here + // because if we did break at this point, that much width would be + // trimmed. + if (textMetrics.mAdvanceWidth - trimmableWidth > availWidth) { + breakAfter = true; + } else { + aLineLayout.NotifyOptionalBreakPosition(this, length, true, + gfxBreakPriority::eNormalBreak); + } + } } // Compute reflow status @@ -8650,7 +8743,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, if (!textStyle->WhiteSpaceIsSignificant() && (lineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY || lineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY || - ShouldSuppressLineBreak()) && + shouldSuppressLineBreak) && !lineContainer->IsSVGText()) { AddStateBits(TEXT_JUSTIFICATION_ENABLED); provider.ComputeJustification(offset, charsFit); @@ -8754,7 +8847,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsRenderingContext* aRC) } nsOverflowAreas -nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState) +nsTextFrame::RecomputeOverflow(nsIFrame* aBlockFrame) { nsRect bounds(nsPoint(0, 0), GetSize()); nsOverflowAreas result(bounds, bounds); @@ -8772,10 +8865,10 @@ nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState) ComputeTransformedLength(provider), gfxFont::LOOSE_INK_EXTENTS, nullptr, &provider); - nsRect boundingBox = RoundOut(textMetrics.mBoundingBox); if (GetWritingMode().IsLineInverted()) { - boundingBox.y = -boundingBox.YMost(); + textMetrics.mBoundingBox.y = -textMetrics.mBoundingBox.YMost(); } + nsRect boundingBox = RoundOut(textMetrics.mBoundingBox); boundingBox += nsPoint(0, mAscent); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. @@ -8784,8 +8877,7 @@ nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState) } nsRect &vis = result.VisualOverflow(); vis.UnionRect(vis, boundingBox); - UnionAdditionalOverflow(PresContext(), aBlockReflowState.frame, provider, - &vis, true); + UnionAdditionalOverflow(PresContext(), aBlockFrame, provider, &vis, true); return result; } @@ -9159,18 +9251,9 @@ nsTextFrame::HasAnyNoncollapsedCharacters() bool nsTextFrame::UpdateOverflow() { - const nsRect rect(nsPoint(0, 0), GetSize()); - nsOverflowAreas overflowAreas(rect, rect); - if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { return false; } - gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated); - if (!mTextRun) { - return false; - } - PropertyProvider provider(this, iter, nsTextFrame::eInflated); - provider.InitializeForDisplay(true); nsIFrame* decorationsBlock; if (IsFloatingFirstLetterChild()) { @@ -9192,8 +9275,8 @@ nsTextFrame::UpdateOverflow() } } - UnionAdditionalOverflow(PresContext(), decorationsBlock, provider, - &overflowAreas.VisualOverflow(), true); + nsOverflowAreas overflowAreas = RecomputeOverflow(decorationsBlock); + return FinishAndStoreOverflow(overflowAreas, GetSize()); } diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 2297d09b63..0a2ff356b2 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -7,6 +7,7 @@ #define nsTextFrame_h__ #include "mozilla/Attributes.h" +#include "mozilla/EventForwards.h" #include "mozilla/gfx/2D.h" #include "nsFrame.h" #include "nsGenericDOMDataNode.h" @@ -40,6 +41,7 @@ public: }; class nsTextFrame : public nsTextFrameBase { + typedef mozilla::TextRangeStyle TextRangeStyle; typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::Rect Rect; @@ -281,8 +283,7 @@ public: TextOffsetType aOffsetType = TextOffsetType::OFFSETS_IN_CONTENT_TEXT) override; - nsOverflowAreas - RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState); + nsOverflowAreas RecomputeOverflow(nsIFrame* aBlockFrame); enum TextRunType { // Anything in reflow (but not intrinsic width calculation) or @@ -745,6 +746,74 @@ protected: bool CombineSelectionUnderlineRect(nsPresContext* aPresContext, nsRect& aRect); + /** + * Utility methods to paint selection. + */ + void DrawSelectionDecorations(gfxContext* aContext, + const gfxRect& aDirtyRect, + SelectionType aType, + nsTextPaintStyle& aTextPaintStyle, + const TextRangeStyle &aRangeStyle, + const gfxPoint& aPt, + gfxFloat aICoordInFrame, + gfxFloat aWidth, + gfxFloat aAscent, + const gfxFont::Metrics& aFontMetrics, + DrawPathCallbacks* aCallbacks, + bool aVertical, + uint8_t aDecoration); + enum DecorationType + { + eNormalDecoration, + eSelectionDecoration + }; + void PaintDecorationLine(gfxContext* const aCtx, + const gfxRect& aDirtyRect, + nscolor aColor, + const nscolor* aOverrideColor, + const gfxPoint& aPt, + gfxFloat aICoordInFrame, + const gfxSize& aLineSize, + gfxFloat aAscent, + gfxFloat aOffset, + uint8_t aDecoration, + uint8_t aStyle, + DecorationType aDecorationType, + DrawPathCallbacks* aCallbacks, + bool aVertical, + gfxFloat aDescentLimit = -1.0); + /** + * ComputeDescentLimitForSelectionUnderline() computes the most far position + * where we can put selection underline. + * + * @return The maximum underline offset from the baseline (positive value + * means that the underline can put below the baseline). + */ + gfxFloat ComputeDescentLimitForSelectionUnderline( + nsPresContext* aPresContext, + const gfxFont::Metrics& aFontMetrics); + /** + * This function encapsulates all knowledge of how selections affect + * foreground and background colors. + * @param aForeground the foreground color to use + * @param aBackground the background color to use, or RGBA(0,0,0,0) if no + * background should be painted + * @return true if the selection affects colors, false otherwise + */ + static bool GetSelectionTextColors(SelectionType aType, + nsTextPaintStyle& aTextPaintStyle, + const TextRangeStyle &aRangeStyle, + nscolor* aForeground, + nscolor* aBackground); + /** + * ComputeSelectionUnderlineHeight() computes selection underline height of + * the specified selection type from the font metrics. + */ + static gfxFloat ComputeSelectionUnderlineHeight( + nsPresContext* aPresContext, + const gfxFont::Metrics& aFontMetrics, + SelectionType aSelectionType); + ContentOffsets GetCharacterOffsetAtFramePointInternal(nsPoint aPoint, bool aForInsertionPoint); diff --git a/layout/reftests/css-ruby/line-break-suppression-5-ref.html b/layout/reftests/css-ruby/line-break-suppression-5-ref.html new file mode 100644 index 0000000000..d646dba0c4 --- /dev/null +++ b/layout/reftests/css-ruby/line-break-suppression-5-ref.html @@ -0,0 +1,10 @@ + + + + + Bug 1186720 - Line break suppression with soft hyphen + + + xa + + diff --git a/layout/reftests/css-ruby/line-break-suppression-5.html b/layout/reftests/css-ruby/line-break-suppression-5.html new file mode 100644 index 0000000000..a44856c8d0 --- /dev/null +++ b/layout/reftests/css-ruby/line-break-suppression-5.html @@ -0,0 +1,10 @@ + + + + + Bug 1186720 - Line break suppression with soft hyphen + + + x + + diff --git a/layout/reftests/css-ruby/reftest.list b/layout/reftests/css-ruby/reftest.list index 18091598f9..9ab3f19c98 100644 --- a/layout/reftests/css-ruby/reftest.list +++ b/layout/reftests/css-ruby/reftest.list @@ -30,6 +30,7 @@ test-pref(dom.meta-viewport.enabled,true) test-pref(font.size.inflation.emPerLin == line-break-suppression-2.html line-break-suppression-2-ref.html == line-break-suppression-3.html line-break-suppression-3-ref.html == line-break-suppression-4.html line-break-suppression-4-ref.html +== line-break-suppression-5.html line-break-suppression-5-ref.html == line-height-1.html line-height-1-ref.html == line-height-2.html line-height-2-ref.html == line-height-3.html line-height-3-ref.html diff --git a/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list b/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list index bf1b104b47..5218255fbc 100644 --- a/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list +++ b/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list @@ -1 +1,2 @@ pref(layout.css.ruby.enabled,true) == ruby-text-decoration-01.html ruby-text-decoration-01-ref.html +== text-decoration-propagation-01.html text-decoration-propagation-01-ref.html diff --git a/layout/reftests/w3c-css/submitted/text-decor-3/text-decoration-propagation-01-ref.html b/layout/reftests/w3c-css/submitted/text-decor-3/text-decoration-propagation-01-ref.html new file mode 100644 index 0000000000..fe5b2191c9 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-decoration-propagation-01-ref.html @@ -0,0 +1,9 @@ + + +CSS Test Reference + + + + This text must not be underlined. + + diff --git a/layout/reftests/w3c-css/submitted/text-decor-3/text-decoration-propagation-01.html b/layout/reftests/w3c-css/submitted/text-decor-3/text-decoration-propagation-01.html new file mode 100644 index 0000000000..45e680d4d0 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-decoration-propagation-01.html @@ -0,0 +1,15 @@ + + +CSS Test: text-decoration shouldn't propagate through 'svg' element + + + + + + + + This text must not be underlined. + + diff --git a/layout/reftests/writing-mode/1175789-underline-overline-1-ref.html b/layout/reftests/writing-mode/1175789-underline-overline-1-ref.html new file mode 100644 index 0000000000..b788d6bae8 --- /dev/null +++ b/layout/reftests/writing-mode/1175789-underline-overline-1-ref.html @@ -0,0 +1,91 @@ + + + + Bug 1175789 - underline and overline in various language + + + +
+
lang="en-US"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="ja"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="ko"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="ja-JP"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="ko-KR"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="zh"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
+ + diff --git a/layout/reftests/writing-mode/1175789-underline-overline-1.html b/layout/reftests/writing-mode/1175789-underline-overline-1.html new file mode 100644 index 0000000000..1044a9dca5 --- /dev/null +++ b/layout/reftests/writing-mode/1175789-underline-overline-1.html @@ -0,0 +1,91 @@ + + + + Bug 1175789 - underline and overline in various language + + + +
+
lang="en-US"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="ja"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="ko"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="ja-JP"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="ko-KR"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
lang="zh"
+
+
+ underline
+ overline +
+
+ underline
+ overline +
+
+
+ + diff --git a/layout/reftests/writing-mode/reftest.list b/layout/reftests/writing-mode/reftest.list index 4fe9f36564..86c600c353 100644 --- a/layout/reftests/writing-mode/reftest.list +++ b/layout/reftests/writing-mode/reftest.list @@ -149,6 +149,7 @@ test-pref(dom.meta-viewport.enabled,true) test-pref(font.size.inflation.emPerLin == 1172774-percent-padding-3.html 1172774-percent-vertical-ref.html == 1172774-percent-padding-4.html 1172774-percent-vertical-ref.html == 1174450-intrinsic-sizing.html 1174450-intrinsic-sizing-ref.html +== 1175789-underline-overline-1.html 1175789-underline-overline-1-ref.html # Suite of tests from Gérard Talbot in bug 1079151 include abspos/reftest.list diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index 2e6bac9af2..3ea10e8b7b 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -39,8 +39,8 @@ GetEventMessageName(EventMessage aMessage) return "NS_COMPOSITION_COMMIT_AS_IS"; case NS_COMPOSITION_COMMIT: return "NS_COMPOSITION_COMMIT"; - case NS_SELECTION_SET: - return "NS_SELECTION_SET"; + case eSetSelection: + return "eSetSelection"; default: return "unacceptable event message"; } @@ -177,7 +177,7 @@ ContentCacheInChild::CacheSelection(nsIWidget* aWidget, mSelection.Clear(); nsEventStatus status = nsEventStatus_eIgnore; - WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, aWidget); + WidgetQueryContentEvent selection(true, eQuerySelectedText, aWidget); aWidget->DispatchEvent(&selection, status); if (NS_WARN_IF(!selection.mSucceeded)) { MOZ_LOG(sContentCacheLog, LogLevel::Error, @@ -219,7 +219,7 @@ ContentCacheInChild::CacheCaret(nsIWidget* aWidget, mCaret.mOffset = mSelection.StartOffset(); nsEventStatus status = nsEventStatus_eIgnore; - WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, aWidget); + WidgetQueryContentEvent caretRect(true, eQueryCaretRect, aWidget); caretRect.InitForQueryCaretRect(mCaret.mOffset); aWidget->DispatchEvent(&caretRect, status); if (NS_WARN_IF(!caretRect.mSucceeded)) { @@ -276,7 +276,7 @@ ContentCacheInChild::CacheText(nsIWidget* aWidget, this, aWidget, GetNotificationName(aNotification))); nsEventStatus status = nsEventStatus_eIgnore; - WidgetQueryContentEvent queryText(true, NS_QUERY_TEXT_CONTENT, aWidget); + WidgetQueryContentEvent queryText(true, eQueryTextContent, aWidget); queryText.InitForQueryTextContent(0, UINT32_MAX); aWidget->DispatchEvent(&queryText, status); if (NS_WARN_IF(!queryText.mSucceeded)) { @@ -516,10 +516,10 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, aEvent.mReply.mFocusedWidget = aWidget; switch (aEvent.mMessage) { - case NS_QUERY_SELECTED_TEXT: + case eQuerySelectedText: MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ mMessage=NS_QUERY_SELECTED_TEXT }, aWidget=0x%p)", + "aEvent={ mMessage=eQuerySelectedText }, aWidget=0x%p)", this, aWidget)); if (NS_WARN_IF(!IsSelectionValid())) { // If content cache hasn't been initialized properly, make the query @@ -557,10 +557,10 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, GetBoolName(aEvent.mReply.mHasSelection), GetWritingModeName(aEvent.mReply.mWritingMode).get())); break; - case NS_QUERY_TEXT_CONTENT: { + case eQueryTextContent: { MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ mMessage=NS_QUERY_TEXT_CONTENT, mInput={ mOffset=%u, " + "aEvent={ mMessage=eQueryTextContent, mInput={ mOffset=%u, " "mLength=%u } }, aWidget=0x%p), mText.Length()=%u", this, aEvent.mInput.mOffset, aEvent.mInput.mLength, aWidget, mText.Length())); @@ -638,10 +638,10 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, GetWritingModeName(aEvent.mReply.mWritingMode).get(), GetRectText(aEvent.mReply.mRect).get())); break; - case NS_QUERY_CARET_RECT: + case eQueryCaretRect: MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ mMessage=NS_QUERY_CARET_RECT, mInput={ mOffset=%u } }, " + "aEvent={ mMessage=eQueryCaretRect, mInput={ mOffset=%u } }, " "aWidget=0x%p), mText.Length()=%u", this, aEvent.mInput.mOffset, aWidget, mText.Length())); if (NS_WARN_IF(!IsSelectionValid())) { diff --git a/widget/ContentCache.h b/widget/ContentCache.h index 955964b56c..79367ac718 100644 --- a/widget/ContentCache.h +++ b/widget/ContentCache.h @@ -282,13 +282,13 @@ public: /** * HandleQueryContentEvent() sets content data to aEvent.mReply. * - * For NS_QUERY_SELECTED_TEXT, fail if the cache doesn't contain the whole + * For eQuerySelectedText, fail if the cache doesn't contain the whole * selected range. (This shouldn't happen because PuppetWidget should have * already sent the whole selection.) * - * For NS_QUERY_TEXT_CONTENT, fail only if the cache doesn't overlap with + * For eQueryTextContent, fail only if the cache doesn't overlap with * the queried range. Note the difference from above. We use - * this behavior because a normal NS_QUERY_TEXT_CONTENT event is allowed to + * this behavior because a normal eQueryTextContent event is allowed to * have out-of-bounds offsets, so that widget can request content without * knowing the exact length of text. It's up to widget to handle cases when * the returned offset/length are different from the queried offset/length. @@ -296,7 +296,7 @@ public: * For NS_QUERY_TEXT_RECT, fail if cached offset/length aren't equals to input. * Cocoa widget always queries selected offset, so it works on it. * - * For NS_QUERY_CARET_RECT, fail if cached offset isn't equals to input + * For eQueryCaretRect, fail if cached offset isn't equals to input * * For NS_QUERY_EDITOR_RECT, always success */ diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 5c11981f92..4900298a90 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -123,10 +123,10 @@ NS_EVENT_MESSAGE(eXULPopupHidden, eXULEventFirst + 3) NS_EVENT_MESSAGE(eXULBroadcast, eXULEventFirst + 5) NS_EVENT_MESSAGE(eXULCommandUpdate, eXULEventFirst + 6) -// Scroll events -NS_EVENT_MESSAGE(NS_MOUSE_SCROLL_START, 1600) -NS_EVENT_MESSAGE(NS_MOUSE_SCROLL, NS_MOUSE_SCROLL_START) -NS_EVENT_MESSAGE(NS_MOUSE_PIXEL_SCROLL, NS_MOUSE_SCROLL_START + 1) +// Legacy mouse scroll (wheel) events +NS_EVENT_MESSAGE(eLegacyMouseScrollEventFirst, 1600) +NS_EVENT_MESSAGE(eLegacyMouseLineOrPageScroll, eLegacyMouseScrollEventFirst) +NS_EVENT_MESSAGE(eLegacyMousePixelScroll, eLegacyMouseScrollEventFirst + 1) NS_EVENT_MESSAGE(NS_SCROLLPORT_START, 1700) NS_EVENT_MESSAGE(NS_SCROLLPORT_UNDERFLOW, NS_SCROLLPORT_START) @@ -212,36 +212,36 @@ NS_EVENT_MESSAGE(eCut, eClipboardEventFirst + 1) NS_EVENT_MESSAGE(ePaste, eClipboardEventFirst + 2) // Query the content information -NS_EVENT_MESSAGE(NS_QUERY_CONTENT_EVENT_START, 3200) +NS_EVENT_MESSAGE(eQueryContentEventFirst, 3200) // Query for the selected text information, it return the selection offset, // selection length and selected text. -NS_EVENT_MESSAGE(NS_QUERY_SELECTED_TEXT, NS_QUERY_CONTENT_EVENT_START) +NS_EVENT_MESSAGE(eQuerySelectedText, eQueryContentEventFirst) // Query for the text content of specified range, it returns actual lengh (if // the specified range is too long) and the text of the specified range. // Returns the entire text if requested length > actual length. -NS_EVENT_MESSAGE(NS_QUERY_TEXT_CONTENT, NS_QUERY_CONTENT_EVENT_START + 1) +NS_EVENT_MESSAGE(eQueryTextContent, eQueryContentEventFirst + 1) // Query for the caret rect of nth insertion point. The offset of the result is // relative position from the top level widget. -NS_EVENT_MESSAGE(NS_QUERY_CARET_RECT, NS_QUERY_CONTENT_EVENT_START + 3) +NS_EVENT_MESSAGE(eQueryCaretRect, eQueryContentEventFirst + 3) // Query for the bounding rect of a range of characters. This works on any // valid character range given offset and length. Result is relative to top // level widget coordinates -NS_EVENT_MESSAGE(NS_QUERY_TEXT_RECT, NS_QUERY_CONTENT_EVENT_START + 4) +NS_EVENT_MESSAGE(NS_QUERY_TEXT_RECT, eQueryContentEventFirst + 4) // Query for the bounding rect of the current focused frame. Result is relative // to top level widget coordinates -NS_EVENT_MESSAGE(NS_QUERY_EDITOR_RECT, NS_QUERY_CONTENT_EVENT_START + 5) +NS_EVENT_MESSAGE(NS_QUERY_EDITOR_RECT, eQueryContentEventFirst + 5) // Query for the current state of the content. The particular members of // mReply that are set for each query content event will be valid on success. -NS_EVENT_MESSAGE(NS_QUERY_CONTENT_STATE, NS_QUERY_CONTENT_EVENT_START + 6) +NS_EVENT_MESSAGE(NS_QUERY_CONTENT_STATE, eQueryContentEventFirst + 6) // Query for the selection in the form of a nsITransferable. -NS_EVENT_MESSAGE(NS_QUERY_SELECTION_AS_TRANSFERABLE, NS_QUERY_CONTENT_EVENT_START + 7) +NS_EVENT_MESSAGE(eQuerySelectionAsTransferable, eQueryContentEventFirst + 7) // Query for character at a point. This returns the character offset, its // rect and also tentative caret point if the point is clicked. The point is // specified by Event::refPoint. -NS_EVENT_MESSAGE(NS_QUERY_CHARACTER_AT_POINT, NS_QUERY_CONTENT_EVENT_START + 8) +NS_EVENT_MESSAGE(NS_QUERY_CHARACTER_AT_POINT, eQueryContentEventFirst + 8) // Query if the DOM element under Event::refPoint belongs to our widget // or not. -NS_EVENT_MESSAGE(NS_QUERY_DOM_WIDGET_HITTEST, NS_QUERY_CONTENT_EVENT_START + 9) +NS_EVENT_MESSAGE(NS_QUERY_DOM_WIDGET_HITTEST, eQueryContentEventFirst + 9) // Video events NS_EVENT_MESSAGE(eMediaEventFirst, 3300) @@ -295,7 +295,7 @@ NS_EVENT_MESSAGE(ePluginInputEvent, ePluginEventFirst) // Events to manipulate selection (WidgetSelectionEvent) NS_EVENT_MESSAGE(eSelectionEventFirst, 3700) // Clear any previous selection and set the given range as the selection -NS_EVENT_MESSAGE(NS_SELECTION_SET, eSelectionEventFirst) +NS_EVENT_MESSAGE(eSetSelection, eSelectionEventFirst) // Events of commands for the contents NS_EVENT_MESSAGE(NS_CONTENT_COMMAND_EVENT_START, 3800) diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h index 8961b15179..cd706d7ce5 100644 --- a/widget/MouseEvents.h +++ b/widget/MouseEvents.h @@ -399,11 +399,11 @@ public: } // The delta value of mouse scroll event. - // If the event message is NS_MOUSE_SCROLL, the value indicates scroll amount - // in lines. However, if the value is nsIDOMUIEvent::SCROLL_PAGE_UP or - // nsIDOMUIEvent::SCROLL_PAGE_DOWN, the value inducates one page scroll. - // If the event message is NS_MOUSE_PIXEL_SCROLL, the value indicates scroll - // amount in pixels. + // If the event message is eLegacyMouseLineOrPageScroll, the value indicates + // scroll amount in lines. However, if the value is + // nsIDOMUIEvent::SCROLL_PAGE_UP or nsIDOMUIEvent::SCROLL_PAGE_DOWN, the + // value inducates one page scroll. If the event message is + // eLegacyMousePixelScroll, the value indicates scroll amount in pixels. int32_t delta; // If this is true, it may cause to scroll horizontally. @@ -499,13 +499,14 @@ public: // If device event handlers don't know when they should set lineOrPageDeltaX // and lineOrPageDeltaY, this is true. Otherwise, false. - // If mIsNoLineOrPageDelta is true, ESM will generate NS_MOUSE_SCROLL events - // when accumulated delta values reach a line height. + // If mIsNoLineOrPageDelta is true, ESM will generate + // eLegacyMouseLineOrPageScroll events when accumulated delta values reach + // a line height. bool mIsNoLineOrPageDelta; // If widget sets lineOrPageDelta, EventStateManager will dispatch - // NS_MOUSE_SCROLL event for compatibility. Note that the delta value means - // pages if the deltaMode is DOM_DELTA_PAGE, otherwise, lines. + // eLegacyMouseLineOrPageScroll event for compatibility. Note that the delta + // value means pages if the deltaMode is DOM_DELTA_PAGE, otherwise, lines. int32_t lineOrPageDeltaX; int32_t lineOrPageDeltaY; diff --git a/widget/TextEvents.h b/widget/TextEvents.h index f24dbc1dc8..75c5588616 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -495,7 +495,7 @@ public: void InitForQueryTextContent(uint32_t aOffset, uint32_t aLength, bool aUseNativeLineBreak = true) { - NS_ASSERTION(mMessage == NS_QUERY_TEXT_CONTENT, + NS_ASSERTION(mMessage == eQueryTextContent, "wrong initializer is called"); mInput.mOffset = aOffset; mInput.mLength = aLength; @@ -505,7 +505,7 @@ public: void InitForQueryCaretRect(uint32_t aOffset, bool aUseNativeLineBreak = true) { - NS_ASSERTION(mMessage == NS_QUERY_CARET_RECT, + NS_ASSERTION(mMessage == eQueryCaretRect, "wrong initializer is called"); mInput.mOffset = aOffset; mUseNativeLineBreak = aUseNativeLineBreak; @@ -530,29 +530,29 @@ public: void RequestFontRanges() { - NS_ASSERTION(mMessage == NS_QUERY_TEXT_CONTENT, + NS_ASSERTION(mMessage == eQueryTextContent, "not querying text content"); mWithFontRanges = true; } uint32_t GetSelectionStart(void) const { - NS_ASSERTION(mMessage == NS_QUERY_SELECTED_TEXT, + NS_ASSERTION(mMessage == eQuerySelectedText, "not querying selection"); return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0); } uint32_t GetSelectionEnd(void) const { - NS_ASSERTION(mMessage == NS_QUERY_SELECTED_TEXT, + NS_ASSERTION(mMessage == eQuerySelectedText, "not querying selection"); return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length()); } mozilla::WritingMode GetWritingMode(void) const { - NS_ASSERTION(mMessage == NS_QUERY_SELECTED_TEXT || - mMessage == NS_QUERY_CARET_RECT || + NS_ASSERTION(mMessage == eQuerySelectedText || + mMessage == eQueryCaretRect || mMessage == NS_QUERY_TEXT_RECT, "not querying selection or text rect"); return mReply.mWritingMode; @@ -593,9 +593,9 @@ public: bool mWidgetIsHit; // mozilla::WritingMode value at the end (focus) of the selection mozilla::WritingMode mWritingMode; - // used by NS_QUERY_SELECTION_AS_TRANSFERABLE + // Used by eQuerySelectionAsTransferable nsCOMPtr mTransferable; - // used by NS_QUERY_TEXT_CONTENT with font ranges requested + // Used by eQueryTextContent with font ranges requested nsAutoTArray mFontRanges; } mReply; diff --git a/widget/cocoa/TextInputHandler.h b/widget/cocoa/TextInputHandler.h index fa554309a2..ce297ba701 100644 --- a/widget/cocoa/TextInputHandler.h +++ b/widget/cocoa/TextInputHandler.h @@ -356,7 +356,7 @@ public: bool DispatchEvent(WidgetGUIEvent& aEvent); /** - * SetSelection() dispatches NS_SELECTION_SET event for the aRange. + * SetSelection() dispatches eSetSelection event for the aRange. * * @param aRange The range which will be selected. * @return TRUE if setting selection is succeeded and diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 6784d865c8..34e76608f5 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -2969,7 +2969,7 @@ IMEInputHandler::ConversationIdentifier() nsRefPtr kungFuDeathGrip(this); // NOTE: The size of NSInteger is same as pointer size. - WidgetQueryContentEvent textContent(true, NS_QUERY_TEXT_CONTENT, mWidget); + WidgetQueryContentEvent textContent(true, eQueryTextContent, mWidget); textContent.InitForQueryTextContent(0, 0); DispatchEvent(textContent); if (!textContent.mSucceeded) { @@ -3005,7 +3005,7 @@ IMEInputHandler::GetAttributedSubstringFromRange(NSRange& aRange, nsRefPtr kungFuDeathGrip(this); nsAutoString str; - WidgetQueryContentEvent textContent(true, NS_QUERY_TEXT_CONTENT, mWidget); + WidgetQueryContentEvent textContent(true, eQueryTextContent, mWidget); textContent.InitForQueryTextContent(aRange.location, aRange.length); textContent.RequestFontRanges(); DispatchEvent(textContent); @@ -3098,7 +3098,7 @@ IMEInputHandler::SelectedRange() nsRefPtr kungFuDeathGrip(this); - WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, mWidget); + WidgetQueryContentEvent selection(true, eQuerySelectedText, mWidget); DispatchEvent(selection); MOZ_LOG(gLog, LogLevel::Info, @@ -3202,7 +3202,7 @@ IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange, } if (useCaretRect) { - WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, mWidget); + WidgetQueryContentEvent caretRect(true, eQueryCaretRect, mWidget); caretRect.InitForQueryCaretRect(aRange.location); DispatchEvent(caretRect); if (!caretRect.mSucceeded) { @@ -3978,7 +3978,7 @@ TextInputHandlerBase::SetSelection(NSRange& aRange) MOZ_ASSERT(!Destroyed()); nsRefPtr kungFuDeathGrip(this); - WidgetSelectionEvent selectionEvent(true, NS_SELECTION_SET, mWidget); + WidgetSelectionEvent selectionEvent(true, eSetSelection, mWidget); selectionEvent.mOffset = aRange.location; selectionEvent.mLength = aRange.length; selectionEvent.mReversed = false; diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 5c048e3f0a..747cd01d34 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -1829,7 +1829,7 @@ nsChildView::ExecuteNativeKeyBinding(NativeKeyBindingsType aType, // the physical direction of the arrow. if (aEvent.keyCode >= nsIDOMKeyEvent::DOM_VK_LEFT && aEvent.keyCode <= nsIDOMKeyEvent::DOM_VK_DOWN) { - WidgetQueryContentEvent query(true, NS_QUERY_SELECTED_TEXT, this); + WidgetQueryContentEvent query(true, eQuerySelectedText, this); DispatchWindowEvent(query); if (query.mSucceeded && query.mReply.mWritingMode.IsVertical()) { @@ -1915,7 +1915,7 @@ NSView* nsChildView::GetEditorView() // We need to get editor's view. E.g., when the focus is in the bookmark // dialog, the view is element of the dialog. At this time, the key // events are processed the parent window's view that has native focus. - WidgetQueryContentEvent textContent(true, NS_QUERY_TEXT_CONTENT, this); + WidgetQueryContentEvent textContent(true, eQueryTextContent, this); textContent.InitForQueryTextContent(0, 0); DispatchWindowEvent(textContent); if (textContent.mSucceeded && textContent.mReply.mFocusedWidget) { @@ -6080,8 +6080,7 @@ PanGestureTypeForEvent(NSEvent* aEvent) return NO; // Obtain the current selection. - WidgetQueryContentEvent event(true, - NS_QUERY_SELECTION_AS_TRANSFERABLE, + WidgetQueryContentEvent event(true, eQuerySelectionAsTransferable, mGeckoChild); mGeckoChild->DispatchWindowEvent(event); if (!event.mSucceeded || !event.mReply.mTransferable) diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp index 9c0d2fc11e..e4945538c6 100644 --- a/widget/gtk/IMContextWrapper.cpp +++ b/widget/gtk/IMContextWrapper.cpp @@ -94,6 +94,80 @@ public: virtual ~GetWritingModeName() {} }; +class GetTextRangeStyleText final : public nsAutoCString +{ +public: + explicit GetTextRangeStyleText(const TextRangeStyle& aStyle) + { + if (!aStyle.IsDefined()) { + AssignLiteral("{ IsDefined()=false }"); + return; + } + + if (aStyle.IsLineStyleDefined()) { + AppendLiteral("{ mLineStyle="); + AppendLineStyle(aStyle.mLineStyle); + if (aStyle.IsUnderlineColorDefined()) { + AppendLiteral(", mUnderlineColor="); + AppendColor(aStyle.mUnderlineColor); + } else { + AppendLiteral(", IsUnderlineColorDefined=false"); + } + } else { + AppendLiteral("{ IsLineStyleDefined()=false"); + } + + if (aStyle.IsForegroundColorDefined()) { + AppendLiteral(", mForegroundColor="); + AppendColor(aStyle.mForegroundColor); + } else { + AppendLiteral(", IsForegroundColorDefined()=false"); + } + + if (aStyle.IsBackgroundColorDefined()) { + AppendLiteral(", mBackgroundColor="); + AppendColor(aStyle.mBackgroundColor); + } else { + AppendLiteral(", IsBackgroundColorDefined()=false"); + } + + AppendLiteral(" }"); + } + void AppendLineStyle(uint8_t aLineStyle) + { + switch (aLineStyle) { + case TextRangeStyle::LINESTYLE_NONE: + AppendLiteral("LINESTYLE_NONE"); + break; + case TextRangeStyle::LINESTYLE_SOLID: + AppendLiteral("LINESTYLE_SOLID"); + break; + case TextRangeStyle::LINESTYLE_DOTTED: + AppendLiteral("LINESTYLE_DOTTED"); + break; + case TextRangeStyle::LINESTYLE_DASHED: + AppendLiteral("LINESTYLE_DASHED"); + break; + case TextRangeStyle::LINESTYLE_DOUBLE: + AppendLiteral("LINESTYLE_DOUBLE"); + break; + case TextRangeStyle::LINESTYLE_WAVY: + AppendLiteral("LINESTYLE_WAVY"); + break; + default: + AppendPrintf("Invalid(0x%02X)", aLineStyle); + break; + } + } + void AppendColor(nscolor aColor) + { + AppendPrintf("{ R=0x%02X, G=0x%02X, B=0x%02X, A=0x%02X }", + NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor), + NS_GET_A(aColor)); + } + virtual ~GetTextRangeStyleText() {}; +}; + const static bool kUseSimpleContextDefault = MOZ_WIDGET_GTK == 2; /****************************************************************************** @@ -1397,21 +1471,21 @@ IMContextWrapper::DispatchCompositionCommitEvent( already_AddRefed IMContextWrapper::CreateTextRangeArray(GtkIMContext* aContext, - const nsAString& aLastDispatchedData) + const nsAString& aCompositionString) { MOZ_LOG(gGtkIMLog, LogLevel::Info, ("GTKIM: %p CreateTextRangeArray(aContext=%p, " - "aLastDispatchedData=\"%s\" (Length()=%u))", - this, aContext, NS_ConvertUTF16toUTF8(aLastDispatchedData).get(), - aLastDispatchedData.Length())); + "aCompositionString=\"%s\" (Length()=%u))", + this, aContext, NS_ConvertUTF16toUTF8(aCompositionString).get(), + aCompositionString.Length())); nsRefPtr textRangeArray = new TextRangeArray(); gchar *preedit_string; - gint cursor_pos; + gint cursor_pos_in_chars; PangoAttrList *feedback_list; gtk_im_context_get_preedit_string(aContext, &preedit_string, - &feedback_list, &cursor_pos); + &feedback_list, &cursor_pos_in_chars); if (!preedit_string || !*preedit_string) { MOZ_LOG(gGtkIMLog, LogLevel::Error, ("GTKIM: %p CreateTextRangeArray(), FAILED, due to " @@ -1422,6 +1496,53 @@ IMContextWrapper::CreateTextRangeArray(GtkIMContext* aContext, return textRangeArray.forget(); } + // Convert caret offset from offset in characters to offset in UTF-16 + // string. If we couldn't proper offset in UTF-16 string, we should + // assume that the caret is at the end of the composition string. + uint32_t caretOffsetInUTF16 = aCompositionString.Length(); + if (NS_WARN_IF(cursor_pos_in_chars < 0)) { + // Note that this case is undocumented. We should assume that the + // caret is at the end of the composition string. + } else if (cursor_pos_in_chars == 0) { + caretOffsetInUTF16 = 0; + } else { + gchar* charAfterCaret = + g_utf8_offset_to_pointer(preedit_string, cursor_pos_in_chars); + if (NS_WARN_IF(!charAfterCaret)) { + MOZ_LOG(gGtkIMLog, LogLevel::Warning, + ("GTKIM: %p CreateTextRangeArray(), failed to get UTF-8 " + "string before the caret (cursor_pos_in_chars=%d)", + this, cursor_pos_in_chars)); + } else { + glong caretOffset = 0; + gunichar2* utf16StrBeforeCaret = + g_utf8_to_utf16(preedit_string, charAfterCaret - preedit_string, + nullptr, &caretOffset, nullptr); + if (NS_WARN_IF(!utf16StrBeforeCaret) || + NS_WARN_IF(caretOffset < 0)) { + MOZ_LOG(gGtkIMLog, LogLevel::Warning, + ("GTKIM: %p CreateTextRangeArray(), WARNING, failed to " + "convert to UTF-16 string before the caret " + "(cursor_pos_in_chars=%d, caretOffset=%d)", + this, cursor_pos_in_chars, caretOffset)); + } else { + caretOffsetInUTF16 = static_cast(caretOffset); + uint32_t compositionStringLength = aCompositionString.Length(); + if (NS_WARN_IF(caretOffsetInUTF16 > compositionStringLength)) { + MOZ_LOG(gGtkIMLog, LogLevel::Warning, + ("GTKIM: %p CreateTextRangeArray(), WARNING, " + "caretOffsetInUTF16=%u is larger than " + "compositionStringLength=%u", + this, caretOffsetInUTF16, compositionStringLength)); + caretOffsetInUTF16 = compositionStringLength; + } + } + if (utf16StrBeforeCaret) { + g_free(utf16StrBeforeCaret); + } + } + } + PangoAttrIterator* iter; iter = pango_attr_list_get_iterator(feedback_list); if (!iter) { @@ -1434,93 +1555,21 @@ IMContextWrapper::CreateTextRangeArray(GtkIMContext* aContext, return textRangeArray.forget(); } - /* - * Depend on gtk2's implementation on XIM support. - * In aFeedback got from gtk2, there are only three types of data: - * PANGO_ATTR_UNDERLINE, PANGO_ATTR_FOREGROUND, PANGO_ATTR_BACKGROUND. - * Corresponding to XIMUnderline, XIMReverse. - * Don't take PANGO_ATTR_BACKGROUND into account, since - * PANGO_ATTR_BACKGROUND and PANGO_ATTR_FOREGROUND are always - * a couple. - */ do { - PangoAttribute* attrUnderline = - pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE); - PangoAttribute* attrForeground = - pango_attr_iterator_get(iter, PANGO_ATTR_FOREGROUND); - if (!attrUnderline && !attrForeground) { + TextRange range; + if (!SetTextRange(iter, preedit_string, caretOffsetInUTF16, range)) { continue; } - - // Get the range of the current attribute(s) - gint start, end; - pango_attr_iterator_range(iter, &start, &end); - - TextRange range; - // XIMReverse | XIMUnderline - if (attrUnderline && attrForeground) { - range.mRangeType = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT; - } - // XIMUnderline - else if (attrUnderline) { - range.mRangeType = NS_TEXTRANGE_CONVERTEDTEXT; - } - // XIMReverse - else if (attrForeground) { - range.mRangeType = NS_TEXTRANGE_SELECTEDRAWTEXT; - } else { - range.mRangeType = NS_TEXTRANGE_RAWINPUT; - } - - gunichar2* uniStr = nullptr; - if (start == 0) { - range.mStartOffset = 0; - } else { - glong uniStrLen; - uniStr = g_utf8_to_utf16(preedit_string, start, - nullptr, &uniStrLen, nullptr); - if (uniStr) { - range.mStartOffset = uniStrLen; - g_free(uniStr); - uniStr = nullptr; - } - } - - glong uniStrLen; - uniStr = g_utf8_to_utf16(preedit_string + start, end - start, - nullptr, &uniStrLen, nullptr); - if (!uniStr) { - range.mEndOffset = range.mStartOffset; - } else { - range.mEndOffset = range.mStartOffset + uniStrLen; - g_free(uniStr); - uniStr = nullptr; - } - textRangeArray->AppendElement(range); - - MOZ_LOG(gGtkIMLog, LogLevel::Debug, - ("GTKIM: %p CreateTextRangeArray(), mStartOffset=%u, " - "mEndOffset=%u, mRangeType=%s", - this, range.mStartOffset, range.mEndOffset, - GetRangeTypeName(range.mRangeType))); } while (pango_attr_iterator_next(iter)); TextRange range; - if (cursor_pos < 0) { - range.mStartOffset = 0; - } else if (uint32_t(cursor_pos) > aLastDispatchedData.Length()) { - range.mStartOffset = aLastDispatchedData.Length(); - } else { - range.mStartOffset = uint32_t(cursor_pos); - } - range.mEndOffset = range.mStartOffset; + range.mStartOffset = range.mEndOffset = caretOffsetInUTF16; range.mRangeType = NS_TEXTRANGE_CARETPOSITION; textRangeArray->AppendElement(range); - MOZ_LOG(gGtkIMLog, LogLevel::Debug, - ("GTKIM: %p CreateTextRangeArray(), mStartOffset=%u, mEndOffset=%u, " - "mRangeType=%s", + ("GTKIM: %p CreateTextRangeArray(), mStartOffset=%u, " + "mEndOffset=%u, mRangeType=%s", this, range.mStartOffset, range.mEndOffset, GetRangeTypeName(range.mRangeType))); @@ -1531,6 +1580,196 @@ IMContextWrapper::CreateTextRangeArray(GtkIMContext* aContext, return textRangeArray.forget(); } +/* static */ +nscolor +IMContextWrapper::ToNscolor(PangoAttrColor* aPangoAttrColor) +{ + PangoColor& pangoColor = aPangoAttrColor->color; + uint8_t r = pangoColor.red / 0x100; + uint8_t g = pangoColor.green / 0x100; + uint8_t b = pangoColor.blue / 0x100; + return NS_RGB(r, g, b); +} + +bool +IMContextWrapper::SetTextRange(PangoAttrIterator* aPangoAttrIter, + const gchar* aUTF8CompositionString, + uint32_t aUTF16CaretOffset, + TextRange& aTextRange) const +{ + // Set the range offsets in UTF-16 string. + gint utf8ClauseStart, utf8ClauseEnd; + pango_attr_iterator_range(aPangoAttrIter, &utf8ClauseStart, &utf8ClauseEnd); + if (utf8ClauseStart == utf8ClauseEnd) { + MOZ_LOG(gGtkIMLog, LogLevel::Error, + ("GTKIM: %p SetTextRange(), FAILED, due to collapsed range", + this)); + return false; + } + + if (!utf8ClauseStart) { + aTextRange.mStartOffset = 0; + } else { + glong utf16PreviousClausesLength; + gunichar2* utf16PreviousClausesString = + g_utf8_to_utf16(aUTF8CompositionString, utf8ClauseStart, nullptr, + &utf16PreviousClausesLength, nullptr); + + if (NS_WARN_IF(!utf16PreviousClausesString)) { + MOZ_LOG(gGtkIMLog, LogLevel::Error, + ("GTKIM: %p SetTextRange(), FAILED, due to g_utf8_to_utf16() " + "failure (retrieving previous string of current clause)", + this)); + return false; + } + + aTextRange.mStartOffset = utf16PreviousClausesLength; + g_free(utf16PreviousClausesString); + } + + glong utf16CurrentClauseLength; + gunichar2* utf16CurrentClauseString = + g_utf8_to_utf16(aUTF8CompositionString + utf8ClauseStart, + utf8ClauseEnd - utf8ClauseStart, + nullptr, &utf16CurrentClauseLength, nullptr); + + if (NS_WARN_IF(!utf16CurrentClauseString)) { + MOZ_LOG(gGtkIMLog, LogLevel::Error, + ("GTKIM: %p SetTextRange(), FAILED, due to g_utf8_to_utf16() " + "failure (retrieving current clause)", + this)); + return false; + } + + aTextRange.mEndOffset = aTextRange.mStartOffset + utf16CurrentClauseLength; + g_free(utf16CurrentClauseString); + utf16CurrentClauseString = nullptr; + + // Set styles + TextRangeStyle& style = aTextRange.mRangeStyle; + + // Underline + PangoAttrInt* attrUnderline = + reinterpret_cast( + pango_attr_iterator_get(aPangoAttrIter, PANGO_ATTR_UNDERLINE)); + if (attrUnderline) { + switch (attrUnderline->value) { + case PANGO_UNDERLINE_NONE: + style.mLineStyle = TextRangeStyle::LINESTYLE_NONE; + break; + case PANGO_UNDERLINE_DOUBLE: + style.mLineStyle = TextRangeStyle::LINESTYLE_DOUBLE; + break; + case PANGO_UNDERLINE_ERROR: + style.mLineStyle = TextRangeStyle::LINESTYLE_WAVY; + break; + case PANGO_UNDERLINE_SINGLE: + case PANGO_UNDERLINE_LOW: + style.mLineStyle = TextRangeStyle::LINESTYLE_SOLID; + break; + default: + MOZ_LOG(gGtkIMLog, LogLevel::Warning, + ("GTKIM: %p SetTextRange(), retrieved unknown underline " + "style: %d", + this, attrUnderline->value)); + style.mLineStyle = TextRangeStyle::LINESTYLE_SOLID; + break; + } + style.mDefinedStyles |= TextRangeStyle::DEFINED_LINESTYLE; + + // Underline color + PangoAttrColor* attrUnderlineColor = + reinterpret_cast( + pango_attr_iterator_get(aPangoAttrIter, + PANGO_ATTR_UNDERLINE_COLOR)); + if (attrUnderlineColor) { + style.mUnderlineColor = ToNscolor(attrUnderlineColor); + style.mDefinedStyles |= TextRangeStyle::DEFINED_UNDERLINE_COLOR; + } + } else { + style.mLineStyle = TextRangeStyle::LINESTYLE_NONE; + style.mDefinedStyles |= TextRangeStyle::DEFINED_LINESTYLE; + } + + // Don't set colors if they are not specified. They should be computed by + // textframe if only one of the colors are specified. + + // Foreground color (text color) + PangoAttrColor* attrForeground = + reinterpret_cast( + pango_attr_iterator_get(aPangoAttrIter, PANGO_ATTR_FOREGROUND)); + if (attrForeground) { + style.mForegroundColor = ToNscolor(attrForeground); + style.mDefinedStyles |= TextRangeStyle::DEFINED_FOREGROUND_COLOR; + } + + // Background color + PangoAttrColor* attrBackground = + reinterpret_cast( + pango_attr_iterator_get(aPangoAttrIter, PANGO_ATTR_BACKGROUND)); + if (attrBackground) { + style.mBackgroundColor = ToNscolor(attrBackground); + style.mDefinedStyles |= TextRangeStyle::DEFINED_BACKGROUND_COLOR; + } + + /** + * We need to judge the meaning of the clause for a11y. Before we support + * IME specific composition string style, we used following rules: + * + * 1: If attrUnderline and attrForground are specified, we assumed the + * clause is NS_TEXTRANGE_SELECTEDCONVERTEDTEXT. + * 2: If only attrUnderline is specified, we assumed the clause is + * NS_TEXTRANGE_CONVERTEDTEXT. + * 3: If only attrForground is specified, we assumed the clause is + * NS_TEXTRANGE_SELECTEDRAWTEXT. + * 4: If neither attrUnderline nor attrForeground is specified, we assumed + * the clause is NS_TEXTRANGE_RAWINPUT. + * + * However, this rules are odd since there can be two or more selected + * clauses. Additionally, our old rules caused that IME developers/users + * cannot specify composition string style as they want. + * + * So, we shouldn't guess the meaning from its visual style. + */ + + if (!attrUnderline && !attrForeground && !attrBackground) { + MOZ_LOG(gGtkIMLog, LogLevel::Warning, + ("GTKIM: %p SetTextRange(), FAILED, due to no attr, " + "aTextRange= { mStartOffset=%u, mEndOffset=%u }", + this, aTextRange.mStartOffset, aTextRange.mEndOffset)); + return false; + } + + // If the range covers whole of composition string and the caret is at + // the end of the composition string, the range is probably not converted. + if (!utf8ClauseStart && + utf8ClauseEnd == static_cast(strlen(aUTF8CompositionString)) && + aTextRange.mEndOffset == aUTF16CaretOffset) { + aTextRange.mRangeType = NS_TEXTRANGE_RAWINPUT; + } + // Typically, the caret is set at the start of the selected clause. + // So, if the caret is in the clause, we can assume that the clause is + // selected. + else if (aTextRange.mStartOffset <= aUTF16CaretOffset && + aTextRange.mEndOffset > aUTF16CaretOffset) { + aTextRange.mRangeType = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT; + } + // Otherwise, we should assume that the clause is converted but not + // selected. + else { + aTextRange.mRangeType = NS_TEXTRANGE_CONVERTEDTEXT; + } + + MOZ_LOG(gGtkIMLog, LogLevel::Debug, + ("GTKIM: %p SetTextRange(), succeeded, aTextRange= { " + "mStartOffset=%u, mEndOffset=%u, mRangeType=%s, mRangeStyle=%s }", + this, aTextRange.mStartOffset, aTextRange.mEndOffset, + GetRangeTypeName(aTextRange.mRangeType), + GetTextRangeStyleText(aTextRange.mRangeStyle).get())); + + return true; +} + void IMContextWrapper::SetCursorPosition(GtkIMContext* aContext) { @@ -1571,7 +1810,7 @@ IMContextWrapper::SetCursorPosition(GtkIMContext* aContext) } WidgetQueryContentEvent charRect(true, - useCaret ? NS_QUERY_CARET_RECT : + useCaret ? eQueryCaretRect : NS_QUERY_TEXT_RECT, mLastFocusedWindow); if (useCaret) { @@ -1594,7 +1833,7 @@ IMContextWrapper::SetCursorPosition(GtkIMContext* aContext) if (!charRect.mSucceeded) { MOZ_LOG(gGtkIMLog, LogLevel::Error, ("GTKIM: %p SetCursorPosition(), FAILED, %s was failed", - this, useCaret ? "NS_QUERY_CARET_RECT" : "NS_QUERY_TEXT_RECT")); + this, useCaret ? "eQueryCaretRect" : "NS_QUERY_TEXT_RECT")); return; } @@ -1670,8 +1909,7 @@ IMContextWrapper::GetCurrentParagraph(nsAString& aText, } // Get all text contents of the focused editor - WidgetQueryContentEvent queryTextContentEvent(true, - NS_QUERY_TEXT_CONTENT, + WidgetQueryContentEvent queryTextContentEvent(true, eQueryTextContent, mLastFocusedWindow); queryTextContentEvent.InitForQueryTextContent(0, UINT32_MAX); mLastFocusedWindow->DispatchEvent(&queryTextContentEvent, status); @@ -1767,8 +2005,7 @@ IMContextWrapper::DeleteText(GtkIMContext* aContext, } // Get all text contents of the focused editor - WidgetQueryContentEvent queryTextContentEvent(true, - NS_QUERY_TEXT_CONTENT, + WidgetQueryContentEvent queryTextContentEvent(true, eQueryTextContent, mLastFocusedWindow); queryTextContentEvent.InitForQueryTextContent(0, UINT32_MAX); mLastFocusedWindow->DispatchEvent(&queryTextContentEvent, status); @@ -1814,7 +2051,7 @@ IMContextWrapper::DeleteText(GtkIMContext* aContext, g_utf8_offset_to_pointer(utf8Str.get(), endInUTF8Characters); // Set selection to delete - WidgetSelectionEvent selectionEvent(true, NS_SELECTION_SET, + WidgetSelectionEvent selectionEvent(true, eSetSelection, mLastFocusedWindow); nsDependentCSubstring utf8StrBeforeOffset(utf8Str, 0, @@ -1913,7 +2150,7 @@ IMContextWrapper::EnsureToCacheSelection(nsAString* aSelectedString) } nsEventStatus status; - WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, + WidgetQueryContentEvent selection(true, eQuerySelectedText, mLastFocusedWindow); InitEvent(selection); mLastFocusedWindow->DispatchEvent(&selection, status); @@ -1962,7 +2199,7 @@ IMContextWrapper::Selection::Assign(const IMENotification& aIMENotification) void IMContextWrapper::Selection::Assign(const WidgetQueryContentEvent& aEvent) { - MOZ_ASSERT(aEvent.mMessage == NS_QUERY_SELECTED_TEXT); + MOZ_ASSERT(aEvent.mMessage == eQuerySelectedText); MOZ_ASSERT(aEvent.mSucceeded); mOffset = aEvent.mReply.mOffset; mLength = aEvent.mReply.mString.Length(); diff --git a/widget/gtk/IMContextWrapper.h b/widget/gtk/IMContextWrapper.h index acc5922d26..f1933b39d8 100644 --- a/widget/gtk/IMContextWrapper.h +++ b/widget/gtk/IMContextWrapper.h @@ -345,13 +345,34 @@ protected: * Generates our text range array from current composition string. * * @param aContext A GtkIMContext which is being handled. - * @param aLastDispatchedData The data of the last compositionchange event - * of current composition. This should be - * mDispatchedCompositionString. + * @param aCompositionString The data to be dispatched with + * compositionchange event. */ already_AddRefed CreateTextRangeArray(GtkIMContext* aContext, - const nsAString& aLastDispatchedData); + const nsAString& aCompositionString); + + /** + * SetTextRange() initializes aTextRange with aPangoAttrIter. + * + * @param aPangoAttrIter An iter which represents a clause of the + * composition string. + * @param aUTF8CompositionString The whole composition string (UTF-8). + * @param aUTF16CaretOffset The caret offset in the composition + * string encoded as UTF-16. + * @param aTextRange The result. + * @return true if this initializes aTextRange. + * Otherwise, false. + */ + bool SetTextRange(PangoAttrIterator* aPangoAttrIter, + const gchar* aUTF8CompositionString, + uint32_t aUTF16CaretOffset, + TextRange& aTextRange) const; + + /** + * ToNscolor() converts the PangoColor in aPangoAttrColor to nscolor. + */ + static nscolor ToNscolor(PangoAttrColor* aPangoAttrColor); /** * Move the candidate window with "fake" cursor position. diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 0acc582391..ad9d3f912b 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -5968,7 +5968,7 @@ nsWindow::ExecuteNativeKeyBinding(NativeKeyBindingsType aType, // Check if we're targeting content with vertical writing mode, // and if so remap the arrow keys. - WidgetQueryContentEvent query(true, NS_QUERY_SELECTED_TEXT, this); + WidgetQueryContentEvent query(true, eQuerySelectedText, this); nsEventStatus status; DispatchEvent(&query, status); diff --git a/widget/tests/TestWinTSF.cpp b/widget/tests/TestWinTSF.cpp index c80357975e..0bb71c55d9 100644 --- a/widget/tests/TestWinTSF.cpp +++ b/widget/tests/TestWinTSF.cpp @@ -1886,12 +1886,12 @@ TestApp::TestSelection(void) bool succeeded = true; /* If these fail the cause is probably one or more of: - * nsTextStore::GetSelection not sending NS_QUERY_SELECTED_TEXT - * NS_QUERY_SELECTED_TEXT not handled by ContentEventHandler - * Bug in NS_QUERY_SELECTED_TEXT handler - * nsTextStore::SetSelection not sending NS_SELECTION_SET - * NS_SELECTION_SET not handled by ContentEventHandler - * Bug in NS_SELECTION_SET handler + * nsTextStore::GetSelection not sending eQuerySelectedText + * eQuerySelectedText not handled by ContentEventHandler + * Bug in eQuerySelectedText handler + * nsTextStore::SetSelection not sending eSetSelection + * eSetSelection not handled by ContentEventHandler + * Bug in eSetSelection handler */ TS_SELECTION_ACP testSel; @@ -1960,12 +1960,12 @@ TestApp::TestText(void) HRESULT hr; /* If these fail the cause is probably one or more of: - * nsTextStore::GetText not sending NS_QUERY_TEXT_CONTENT - * NS_QUERY_TEXT_CONTENT not handled by ContentEventHandler - * Bug in NS_QUERY_TEXT_CONTENT handler + * nsTextStore::GetText not sending eQueryTextContent + * eQueryTextContent not handled by ContentEventHandler + * Bug in eQueryTextContent handler * nsTextStore::SetText not calling SetSelection or InsertTextAtSelection * Bug in SetSelection or InsertTextAtSelection - * NS_SELECTION_SET bug or NS_COMPOSITION_* / NS_COMPOSITION_CHANGE bug + * eSetSelection bug or NS_COMPOSITION_* / NS_COMPOSITION_CHANGE bug */ if (!mMgr->GetFocusedStore()) { diff --git a/widget/windows/IMMHandler.cpp b/widget/windows/IMMHandler.cpp index 7f37c8c86f..043c1855fa 100644 --- a/widget/windows/IMMHandler.cpp +++ b/widget/windows/IMMHandler.cpp @@ -1726,14 +1726,13 @@ IMMHandler::HandleDocumentFeed(nsWindow* aWindow, } // Get all contents of the focused editor. - WidgetQueryContentEvent textContent(true, NS_QUERY_TEXT_CONTENT, aWindow); + WidgetQueryContentEvent textContent(true, eQueryTextContent, aWindow); textContent.InitForQueryTextContent(0, UINT32_MAX); aWindow->InitEvent(textContent, &point); aWindow->DispatchWindowEvent(&textContent); if (!textContent.mSucceeded) { MOZ_LOG(gIMMLog, LogLevel::Error, - ("IMM: HandleDocumentFeed, FAILED, due to NS_QUERY_TEXT_CONTENT " - "failure")); + ("IMM: HandleDocumentFeed, FAILED, due to eQueryTextContent failure")); return false; } @@ -2203,13 +2202,13 @@ IMMHandler::GetCaretRect(nsWindow* aWindow, return false; } - WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, aWindow); + WidgetQueryContentEvent caretRect(true, eQueryCaretRect, aWindow); caretRect.InitForQueryCaretRect(selection.mOffset); aWindow->InitEvent(caretRect, &point); aWindow->DispatchWindowEvent(&caretRect); if (!caretRect.mSucceeded) { MOZ_LOG(gIMMLog, LogLevel::Info, - ("IMM: GetCaretRect, FAILED, due to NS_QUERY_CARET_RECT failure")); + ("IMM: GetCaretRect, FAILED, due to eQueryCaretRect failure")); return false; } aCaretRect = LayoutDevicePixel::ToUntyped(caretRect.mReply.mRect); @@ -2753,14 +2752,13 @@ IMMHandler::Selection::Init(nsWindow* aWindow) { Clear(); - WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, aWindow); + WidgetQueryContentEvent selection(true, eQuerySelectedText, aWindow); nsIntPoint point(0, 0); aWindow->InitEvent(selection, &point); aWindow->DispatchWindowEvent(&selection); if (NS_WARN_IF(!selection.mSucceeded)) { MOZ_LOG(gIMMLog, LogLevel::Error, - ("IMM: Selection::Init, FAILED, due to NS_QUERY_SELECTED_TEXT " - "failure")); + ("IMM: Selection::Init, FAILED, due to eQuerySelectedText failure")); return false; } // If the window is destroyed during querying selected text, we shouldn't diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index 1cef5fcdd3..8383a83ba4 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -1301,7 +1301,7 @@ TSFTextStore::TSFTextStore() , mPendingOnSelectionChange(false) , mPendingOnLayoutChange(false) , mPendingDestroy(false) - , mPendingClearLockedContent(false) + , mDeferClearingLockedContent(false) , mNativeCaretIsCreated(false) , mDeferNotifyingTSF(false) { @@ -1674,11 +1674,6 @@ TSFTextStore::FlushPendingActions() return; } - // If dispatching event causes NOTIFY_IME_OF_COMPOSITION_UPDATE, we should - // wait to abandon mLockedContent until it's notified because the dispatched - // event may be handled asynchronously in e10s mode. - mPendingClearLockedContent = !mPendingActions.Length(); - nsRefPtr kungFuDeathGrip(mWidget); for (uint32_t i = 0; i < mPendingActions.Length(); i++) { PendingAction& action = mPendingActions[i]; @@ -1692,7 +1687,7 @@ TSFTextStore::FlushPendingActions() if (action.mAdjustSelection) { // Select composition range so the new composition replaces the range - WidgetSelectionEvent selectionSet(true, NS_SELECTION_SET, mWidget); + WidgetSelectionEvent selectionSet(true, eSetSelection, mWidget); mWidget->InitEvent(selectionSet); selectionSet.mOffset = static_cast(action.mSelectionStart); selectionSet.mLength = static_cast(action.mSelectionLength); @@ -1701,7 +1696,7 @@ TSFTextStore::FlushPendingActions() if (!selectionSet.mSucceeded) { MOZ_LOG(sTextStoreLog, LogLevel::Error, ("TSF: 0x%p TSFTextStore::FlushPendingActions() " - "FAILED due to NS_SELECTION_SET failure", this)); + "FAILED due to eSetSelection failure", this)); break; } } @@ -1712,7 +1707,9 @@ TSFTextStore::FlushPendingActions() mWidget); mWidget->InitEvent(compositionStart); // NS_COMPOSITION_START always causes NOTIFY_IME_OF_COMPOSITION_UPDATE. - mPendingClearLockedContent = true; + // Therefore, we should wait to clear the locked content until it's + // notified. + mDeferClearingLockedContent = true; DispatchEvent(compositionStart); if (!mWidget || mWidget->Destroyed()) { break; @@ -1777,9 +1774,11 @@ TSFTextStore::FlushPendingActions() } compositionChange.mRanges = action.mRanges; // When the NS_COMPOSITION_CHANGE causes a DOM text event, - // NOTIFY_IME_OF_COMPOSITION_UPDATE will be notified. + // the IME will be notified of NOTIFY_IME_OF_COMPOSITION_UPDATE. In + // such case, we should not clear the locked content until we notify + // the IME of the composition update. if (compositionChange.CausesDOMTextEvent()) { - mPendingClearLockedContent = true; + mDeferClearingLockedContent = true; } DispatchEvent(compositionChange); // Be aware, the mWidget might already have been destroyed. @@ -1802,9 +1801,11 @@ TSFTextStore::FlushPendingActions() mWidget->InitEvent(compositionCommit); compositionCommit.mData = action.mData; // When the NS_COMPOSITION_COMMIT causes a DOM text event, - // NOTIFY_IME_OF_COMPOSITION_UPDATE will be notified. + // the IME will be notified of NOTIFY_IME_OF_COMPOSITION_UPDATE. In + // such case, we should not clear the locked content until we notify + // the IME of the composition update. if (compositionCommit.CausesDOMTextEvent()) { - mPendingClearLockedContent = true; + mDeferClearingLockedContent = true; } DispatchEvent(compositionCommit); if (!mWidget || mWidget->Destroyed()) { @@ -1812,15 +1813,15 @@ TSFTextStore::FlushPendingActions() } break; } - case PendingAction::SELECTION_SET: { + case PendingAction::SET_SELECTION: { MOZ_LOG(sTextStoreLog, LogLevel::Debug, ("TSF: 0x%p TSFTextStore::FlushPendingActions() " - "flushing SELECTION_SET={ mSelectionStart=%d, " + "flushing SET_SELECTION={ mSelectionStart=%d, " "mSelectionLength=%d, mSelectionReversed=%s }", this, action.mSelectionStart, action.mSelectionLength, GetBoolName(action.mSelectionReversed))); - WidgetSelectionEvent selectionSet(true, NS_SELECTION_SET, mWidget); + WidgetSelectionEvent selectionSet(true, eSetSelection, mWidget); selectionSet.mOffset = static_cast(action.mSelectionStart); selectionSet.mLength = @@ -1868,9 +1869,11 @@ TSFTextStore::MaybeFlushPendingNotifications() return; } - if (mPendingClearLockedContent) { - mPendingClearLockedContent = false; + if (!mDeferClearingLockedContent && mLockedContent.IsInitialized()) { mLockedContent.Clear(); + MOZ_LOG(sTextStoreLog, LogLevel::Debug, + ("TSF: 0x%p TSFTextStore::MaybeFlushPendingNotifications(), " + "mLockedContent is cleared", this)); } if (mPendingOnLayoutChange) { @@ -1997,12 +2000,21 @@ TSFTextStore::LockedContent() // This should be called when the document is locked or the content hasn't // been abandoned yet. if (NS_WARN_IF(!IsReadLocked() && !mLockedContent.IsInitialized())) { + MOZ_LOG(sTextStoreLog, LogLevel::Error, + ("TSF: 0x%p TSFTextStore::LockedContent(), FAILED, due to " + "called wrong timing, IsReadLocked()=%s, " + "mLockedContent.IsInitialized()=%s", + this, GetBoolName(IsReadLocked()), + GetBoolName(mLockedContent.IsInitialized()))); mLockedContent.Clear(); return mLockedContent; } Selection& currentSel = CurrentSelection(); if (currentSel.IsDirty()) { + MOZ_LOG(sTextStoreLog, LogLevel::Error, + ("TSF: 0x%p TSFTextStore::LockedContent(), FAILED, due to " + "CurrentSelection() failure", this)); mLockedContent.Clear(); return mLockedContent; } @@ -2010,19 +2022,31 @@ TSFTextStore::LockedContent() if (!mLockedContent.IsInitialized()) { nsAutoString text; if (NS_WARN_IF(!GetCurrentText(text))) { + MOZ_LOG(sTextStoreLog, LogLevel::Error, + ("TSF: 0x%p TSFTextStore::LockedContent(), FAILED, due to " + "GetCurrentText() failure", this)); mLockedContent.Clear(); return mLockedContent; } mLockedContent.Init(text); + // Basically, the locked content should be cleared after the document is + // unlocked. However, in e10s mode, content will be modified + // asynchronously. In such case, mDeferClearingLockedContent may be + // true even after the document is unlocked. + mDeferClearingLockedContent = false; } MOZ_LOG(sTextStoreLog, LogLevel::Debug, ("TSF: 0x%p TSFTextStore::LockedContent(): " - "mLockedContent={ mText.Length()=%d, mLastCompositionString=\"%s\", " + "mLockedContent={ mText=\"%s\" (Length()=%u), " + "mLastCompositionString=\"%s\" (Length()=%u), " "mMinTextModifiedOffset=%u }", - this, mLockedContent.Text().Length(), + this, mLockedContent.Text().Length() <= 20 ? + NS_ConvertUTF16toUTF8(mLockedContent.Text()).get() : "", + mLockedContent.Text().Length(), NS_ConvertUTF16toUTF8(mLockedContent.LastCompositionString()).get(), + mLockedContent.LastCompositionString().Length(), mLockedContent.MinTextModifiedOffset())); return mLockedContent; @@ -2038,11 +2062,18 @@ TSFTextStore::GetCurrentText(nsAString& aTextContent) MOZ_ASSERT(mWidget && !mWidget->Destroyed()); - WidgetQueryContentEvent queryText(true, NS_QUERY_TEXT_CONTENT, mWidget); + MOZ_LOG(sTextStoreLog, LogLevel::Debug, + ("TSF: 0x%p TSFTextStore::GetCurrentText(): " + "retrieving text from the content...", this)); + + WidgetQueryContentEvent queryText(true, eQueryTextContent, mWidget); queryText.InitForQueryTextContent(0, UINT32_MAX); mWidget->InitEvent(queryText); DispatchEvent(queryText); if (NS_WARN_IF(!queryText.mSucceeded)) { + MOZ_LOG(sTextStoreLog, LogLevel::Error, + ("TSF: 0x%p TSFTextStore::GetCurrentText(), FAILED, due to " + "eQueryTextContent failure", this)); aTextContent.Truncate(); return false; } @@ -2061,8 +2092,7 @@ TSFTextStore::CurrentSelection() MOZ_CRASH(); } - WidgetQueryContentEvent querySelection(true, NS_QUERY_SELECTED_TEXT, - mWidget); + WidgetQueryContentEvent querySelection(true, eQuerySelectedText, mWidget); mWidget->InitEvent(querySelection); DispatchEvent(querySelection); NS_ENSURE_TRUE(querySelection.mSucceeded, mSelection); @@ -2664,7 +2694,7 @@ TSFTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, CompleteLastActionIfStillIncomplete(); PendingAction* action = mPendingActions.AppendElement(); - action->mType = PendingAction::SELECTION_SET; + action->mType = PendingAction::SET_SELECTION; action->mSelectionStart = pSelection->acpStart; action->mSelectionLength = pSelection->acpEnd - pSelection->acpStart; action->mSelectionReversed = (pSelection->style.ase == TS_AE_START); @@ -4676,7 +4706,9 @@ TSFTextStore::OnUpdateCompositionInternal() "mDeferNotifyingTSF=%s", this, GetBoolName(mDeferNotifyingTSF))); - mPendingClearLockedContent = true; + // Now, all sent composition events are handled by the content even in + // e10s mode. + mDeferClearingLockedContent = false; mDeferNotifyingTSF = false; MaybeFlushPendingNotifications(); return NS_OK; @@ -4779,14 +4811,14 @@ TSFTextStore::CreateNativeCaret() // collapsed, is it OK? uint32_t caretOffset = currentSel.MaxOffset(); - WidgetQueryContentEvent queryCaretRect(true, NS_QUERY_CARET_RECT, mWidget); + WidgetQueryContentEvent queryCaretRect(true, eQueryCaretRect, mWidget); queryCaretRect.InitForQueryCaretRect(caretOffset); mWidget->InitEvent(queryCaretRect); DispatchEvent(queryCaretRect); if (!queryCaretRect.mSucceeded) { MOZ_LOG(sTextStoreLog, LogLevel::Error, ("TSF: 0x%p TSFTextStore::CreateNativeCaret() FAILED due to " - "NS_QUERY_CARET_RECT failure (offset=%d)", this, caretOffset)); + "eQueryCaretRect failure (offset=%d)", this, caretOffset)); return; } diff --git a/widget/windows/TSFTextStore.h b/widget/windows/TSFTextStore.h index 410f2615ef..7e3c680db0 100644 --- a/widget/windows/TSFTextStore.h +++ b/widget/windows/TSFTextStore.h @@ -511,7 +511,7 @@ protected: COMPOSITION_START, COMPOSITION_UPDATE, COMPOSITION_END, - SELECTION_SET + SET_SELECTION }; ActionType mType; // For compositionstart and selectionset @@ -793,9 +793,9 @@ protected: // During the documet is locked, we shouldn't destroy the instance. // If this is true, the instance will be destroyed after unlocked. bool mPendingDestroy; - // If this is true, MaybeFlushPendingNotifications() will clear the + // If this is false, MaybeFlushPendingNotifications() will clear the // mLockedContent. - bool mPendingClearLockedContent; + bool mDeferClearingLockedContent; // While there is native caret, this is true. Otherwise, false. bool mNativeCaretIsCreated; // While the instance is dispatching events, the event may not be handled