diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp index 084743070a3..9ce70e6e151 100644 --- a/dom/events/ContentEventHandler.cpp +++ b/dom/events/ContentEventHandler.cpp @@ -203,13 +203,13 @@ ContentEventHandler::QueryContentRect(nsIContent* aContent, // get rect for first frame nsRect resultRect(nsPoint(0, 0), frame->GetRect().Size()); - nsresult rv = ConvertToRootViewRelativeOffset(frame, resultRect); + nsresult rv = ConvertToRootRelativeOffset(frame, resultRect); NS_ENSURE_SUCCESS(rv, rv); // account for any additional frames while ((frame = frame->GetNextContinuation()) != nullptr) { nsRect frameRect(nsPoint(0, 0), frame->GetRect().Size()); - rv = ConvertToRootViewRelativeOffset(frame, frameRect); + rv = ConvertToRootRelativeOffset(frame, frameRect); NS_ENSURE_SUCCESS(rv, rv); resultRect.UnionRect(resultRect, frameRect); } @@ -1017,7 +1017,7 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent) // get the starting frame rect nsRect rect(nsPoint(0, 0), firstFrame->GetRect().Size()); - rv = ConvertToRootViewRelativeOffset(firstFrame, rect); + rv = ConvertToRootRelativeOffset(firstFrame, rect); NS_ENSURE_SUCCESS(rv, rv); nsRect frameRect = rect; nsPoint ptOffset; @@ -1059,7 +1059,7 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent) } } frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size()); - rv = ConvertToRootViewRelativeOffset(frame, frameRect); + rv = ConvertToRootRelativeOffset(frame, frameRect); NS_ENSURE_SUCCESS(rv, rv); if (frame != lastFrame) { // not last frame, so just add rect to previous result @@ -1125,7 +1125,7 @@ ContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent) lineBreakType); NS_ENSURE_SUCCESS(rv, rv); if (offset == aEvent->mInput.mOffset) { - rv = ConvertToRootViewRelativeOffset(caretFrame, caretRect); + rv = ConvertToRootRelativeOffset(caretFrame, caretRect); NS_ENSURE_SUCCESS(rv, rv); nscoord appUnitsPerDevPixel = caretFrame->PresContext()->AppUnitsPerDevPixel(); @@ -1186,7 +1186,7 @@ ContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent) rect.height = fontHeight; } - rv = ConvertToRootViewRelativeOffset(frame, rect); + rv = ConvertToRootRelativeOffset(frame, rect); NS_ENSURE_SUCCESS(rv, rv); aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped( @@ -1547,18 +1547,21 @@ ContentEventHandler::GetStartFrameAndOffset(const nsRange* aRange, } nsresult -ContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame, - nsRect& aRect) +ContentEventHandler::ConvertToRootRelativeOffset(nsIFrame* aFrame, + nsRect& aRect) { NS_ASSERTION(aFrame, "aFrame must not be null"); - nsView* view = nullptr; - nsPoint posInView; - aFrame->GetOffsetFromView(posInView, &view); - if (!view) { + nsPresContext* rootPresContext = aFrame->PresContext()->GetRootPresContext(); + if (NS_WARN_IF(!rootPresContext)) { return NS_ERROR_FAILURE; } - aRect += posInView + view->GetOffsetTo(nullptr); + nsIFrame* rootFrame = rootPresContext->PresShell()->GetRootFrame(); + if (NS_WARN_IF(!rootFrame)) { + return NS_ERROR_FAILURE; + } + + aRect = nsLayoutUtils::TransformFrameRectToAncestor(aFrame, aRect, rootFrame); return NS_OK; } diff --git a/dom/events/ContentEventHandler.h b/dom/events/ContentEventHandler.h index 2707789e4a9..80810a3b15a 100644 --- a/dom/events/ContentEventHandler.h +++ b/dom/events/ContentEventHandler.h @@ -136,9 +136,10 @@ protected: nsresult GetStartFrameAndOffset(const nsRange* aRange, nsIFrame*& aFrame, int32_t& aOffsetInFrame); - // Convert the frame relative offset to the root view relative offset. - nsresult ConvertToRootViewRelativeOffset(nsIFrame* aFrame, - nsRect& aRect); + // Convert the frame relative offset to the root frame of the root presContext + // relative offset. + nsresult ConvertToRootRelativeOffset(nsIFrame* aFrame, + nsRect& aRect); // Expand aXPOffset to the nearest offset in cluster boundary. aForward is // true, it is expanded to forward. nsresult ExpandToClusterBoundary(nsIContent* aContent, bool aForward, diff --git a/widget/TextEvents.h b/widget/TextEvents.h index 44dab1b6294..8f6e999f169 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -582,7 +582,11 @@ public: // This is the offset where caret would be if user clicked at the refPoint. uint32_t mTentativeCaretOffset; nsString mString; - // Finally, the coordinates is system coordinates. + // mRect is used by eQueryTextRect, eQueryCaretRect, eQueryCharacterAtPoint + // and eQueryEditorRect. The coordinates is system coordinates relative to + // the top level widget of mFocusedWidget. E.g., if a which + // is owned by a window has focused editor, the offset of mRect is relative + // to the owner window, not the . mozilla::LayoutDeviceIntRect mRect; // The return widget has the caret. This is set at all query events. nsIWidget* mFocusedWidget; diff --git a/widget/tests/window_composition_text_querycontent.xul b/widget/tests/window_composition_text_querycontent.xul index cbe256bc0d7..2b61e8cfc58 100644 --- a/widget/tests/window_composition_text_querycontent.xul +++ b/widget/tests/window_composition_text_querycontent.xul @@ -2309,6 +2309,86 @@ function runCharAtPointAtOutsideTest() } } +function runCSSTransformTest() +{ + textarea.focus(); + textarea.value = "some text"; + textarea.selectionStart = textarea.selectionEnd = textarea.value.length; + var editorRect = synthesizeQueryEditorRect(); + if (!checkQueryContentResult(editorRect, + "runCSSTransformTest: editorRect")) { + return; + } + var firstCharRect = synthesizeQueryTextRect(0, 1); + if (!checkQueryContentResult(firstCharRect, + "runCSSTransformTest: firstCharRect")) { + return; + } + var lastCharRect = synthesizeQueryTextRect(textarea.value.length - 1, textarea.value.length); + if (!checkQueryContentResult(lastCharRect, + "runCSSTransformTest: lastCharRect")) { + return; + } + var caretRect = synthesizeQueryCaretRect(textarea.selectionStart); + if (!checkQueryContentResult(caretRect, + "runCSSTransformTest: caretRect")) { + return; + } + var caretRectBeforeFirstChar = synthesizeQueryCaretRect(0); + if (!checkQueryContentResult(caretRectBeforeFirstChar, + "runCSSTransformTest: caretRectBeforeFirstChar")) { + return; + } + + try { + textarea.style.transform = "translate(10px, 15px)"; + function movedRect(aRect, aX, aY) + { + return { left: aRect.left + aX, top: aRect.top + aY, width: aRect.width, height: aRect.height } + } + + var editorRectTranslated = synthesizeQueryEditorRect(); + if (!checkQueryContentResult(editorRectTranslated, + "runCSSTransformTest: editorRectTranslated") || + !checkRect(editorRectTranslated, movedRect(editorRect, 10, 15), + "runCSSTransformTest: editorRectTranslated")) { + return; + } + var firstCharRectTranslated = synthesizeQueryTextRect(0, 1); + if (!checkQueryContentResult(firstCharRectTranslated, + "runCSSTransformTest: firstCharRectTranslated") || + !checkRect(firstCharRectTranslated, movedRect(firstCharRect, 10, 15), + "runCSSTransformTest: firstCharRectTranslated")) { + return; + } + var lastCharRectTranslated = synthesizeQueryTextRect(textarea.value.length - 1, textarea.value.length); + if (!checkQueryContentResult(lastCharRectTranslated, + "runCSSTransformTest: lastCharRectTranslated") || + !checkRect(lastCharRectTranslated, movedRect(lastCharRect, 10, 15), + "runCSSTransformTest: lastCharRectTranslated")) { + return; + } + var caretRectTranslated = synthesizeQueryCaretRect(textarea.selectionStart); + if (!checkQueryContentResult(caretRectTranslated, + "runCSSTransformTest: caretRectTranslated") || + !checkRect(caretRectTranslated, movedRect(caretRect, 10, 15), + "runCSSTransformTest: caretRectTranslated")) { + return; + } + var caretRectBeforeFirstCharTranslated = synthesizeQueryCaretRect(0); + if (!checkQueryContentResult(caretRectBeforeFirstCharTranslated, + "runCSSTransformTest: caretRectBeforeFirstCharTranslated") || + !checkRect(caretRectBeforeFirstCharTranslated, movedRect(caretRectBeforeFirstChar, 10, 15), + "runCSSTransformTest: caretRectBeforeFirstCharTranslated")) { + return; + } + + // XXX It's too difficult to check the result with scale and rotate... + } finally { + textarea.style.transform = ""; + } +} + function runBug722639Test() { textarea.focus(); @@ -4522,6 +4602,7 @@ function runTest() runCompositionEventTest(); runCharAtPointTest(textarea, "textarea in the document"); runCharAtPointAtOutsideTest(); + runCSSTransformTest(); runBug722639Test(); runForceCommitTest(); runNestedSettingValue();