From 17e13c22fc92cb2b02263186f6abffc976531d91 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 26 Jun 2025 17:19:47 +0100 Subject: [PATCH] Android: Fix scaling of bounds and input coordinates for components using a custom desktop scale factor --- .../native/juce_Windowing_android.cpp | 45 ++++++++++--------- .../juce_opengl/native/juce_OpenGL_android.h | 31 ++++++------- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/modules/juce_gui_basics/native/juce_Windowing_android.cpp b/modules/juce_gui_basics/native/juce_Windowing_android.cpp index d0aceb0ddf..98cd848509 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_android.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_android.cpp @@ -1375,7 +1375,8 @@ public: LocalRef viewLayoutParams { env->NewObject (AndroidLayoutParams, AndroidLayoutParams.create, -2, -2) }; env->CallVoidMethod (view.get(), AndroidView.setLayoutParams, viewLayoutParams.get()); - auto physicalBounds = (comp.getBoundsInParent().toFloat() * scale).toNearestInt(); + const auto rawPeerBounds = detail::ComponentHelpers::localPositionToRawPeerPos (comp, comp.getBoundsInParent().toFloat()); + const auto physicalBounds = Desktop::getInstance().getDisplays().logicalToPhysical (rawPeerBounds).toNearestInt(); view.callVoidMethod (AndroidView.layout, physicalBounds.getX(), physicalBounds.getY(), physicalBounds.getRight(), physicalBounds.getBottom()); @@ -1480,7 +1481,7 @@ public: void setBounds (const Rectangle& userRect, bool isNowFullScreen) override { - auto bounds = (userRect.toFloat() * scale).toNearestInt(); + auto bounds = Desktop::getInstance().getDisplays().logicalToPhysical (userRect); if (MessageManager::getInstance()->isThisTheMessageThread()) { @@ -1531,7 +1532,7 @@ public: view.callIntMethod (AndroidView.getWidth), view.callIntMethod (AndroidView.getHeight)); - return (bounds.toFloat() / scale).toNearestInt(); + return Desktop::getInstance().getDisplays().physicalToLogical (bounds); } void handleScreenSizeChange() override @@ -1544,19 +1545,20 @@ public: Point getScreenPosition() const { - return getViewLocationOnScreen (getEnv(), view.get()); + const auto physical = getViewLocationOnScreen (getEnv(), view.get()); + return Desktop::getInstance().getDisplays().physicalToLogical (physical); } Point localToGlobal (Point relativePosition) override { - return relativePosition + (getScreenPosition().toFloat() / scale); + return relativePosition + (getScreenPosition().toFloat()); } using ComponentPeer::localToGlobal; Point globalToLocal (Point screenPosition) override { - return screenPosition - (getScreenPosition().toFloat() / scale); + return screenPosition - (getScreenPosition().toFloat()); } using ComponentPeer::globalToLocal; @@ -1608,13 +1610,10 @@ public: // n/a } - bool contains (Point localPos, bool trueIfInAChildWindow) const override + bool contains (Point localPos, bool) const override { - return isPositiveAndBelow (localPos.x, component.getWidth()) - && isPositiveAndBelow (localPos.y, component.getHeight()) - && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint, - (float) localPos.x * scale, - (float) localPos.y * scale)); + const auto scaled = detail::ComponentHelpers::rawPeerPositionToLocal (component, localPos); + return component.getLocalBounds().contains (scaled); } OptionalBorderSize getFrameSizeIfPresent() const override @@ -1658,7 +1657,7 @@ public: //============================================================================== void handleMouseDownCallback (int index, Point sysPos, int64 time) { - lastMousePos = sysPos / scale; + lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos); auto pos = globalToLocal (lastMousePos); // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. @@ -1677,7 +1676,7 @@ public: void handleMouseDragCallback (int index, Point sysPos, int64 time) { - lastMousePos = sysPos / scale; + lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos); auto pos = globalToLocal (lastMousePos); jassert (index < 64); @@ -1697,7 +1696,7 @@ public: void handleMouseUpCallback (int index, Point sysPos, int64 time) { - lastMousePos = sysPos / scale; + lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos); auto pos = globalToLocal (lastMousePos); jassert (index < 64); @@ -1739,7 +1738,10 @@ public: if (auto* topHandler = component.getAccessibilityHandler()) { - if (auto* virtualHandler = topHandler->getChildAt ((sysPos / scale).roundToInt())) + const auto rawPeerPos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos); + const auto localPos = detail::ComponentHelpers::rawPeerPositionToLocal (component, rawPeerPos); + + if (auto* virtualHandler = topHandler->getChildAt (localPos.roundToInt())) { switch (command) { @@ -1952,12 +1954,11 @@ public: static void handlePaintCallback (JNIEnv* env, AndroidComponentPeer& t, jobject canvas, jobject paint) { - jobject rect = env->CallObjectMethod (canvas, AndroidCanvas.getClipBounds); + LocalRef rect { env->CallObjectMethod (canvas, AndroidCanvas.getClipBounds) }; auto left = env->GetIntField (rect, AndroidRect.left); auto top = env->GetIntField (rect, AndroidRect.top); auto right = env->GetIntField (rect, AndroidRect.right); auto bottom = env->GetIntField (rect, AndroidRect.bottom); - env->DeleteLocalRef (rect); auto clip = Rectangle::leftTopRightBottom (left, top, right, bottom); @@ -1982,7 +1983,9 @@ public: { LowLevelGraphicsSoftwareRenderer g (temp); g.setOrigin (-clip.getPosition()); - g.addTransform (AffineTransform::scale (t.scale)); + const auto scale = Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale + / Desktop::getInstance().getGlobalScaleFactor(); + g.addTransform (AffineTransform::scale ((float) scale)); t.handlePaint (g); } } @@ -1997,7 +2000,7 @@ public: void repaint (const Rectangle& userArea) override { - auto area = (userArea.toFloat() * scale).toNearestInt(); + const auto area = Desktop::getInstance().getDisplays().logicalToPhysical (userArea.toFloat()).toNearestInt(); GlobalRef localView (view); @@ -2188,7 +2191,6 @@ private: METHOD (setViewName, "setViewName", "(Ljava/lang/String;)V") \ METHOD (setVisible, "setVisible", "(Z)V") \ METHOD (isVisible, "isVisible", "()Z") \ - METHOD (containsPoint, "containsPoint", "(II)Z") \ METHOD (showKeyboard, "showKeyboard", "(III)V") \ METHOD (hideKeyboard, "hideKeyboard", "()V") \ METHOD (closeInputMethodContext, "closeInputMethodContext", "()V") \ @@ -2467,7 +2469,6 @@ private: GlobalRef view, viewGroup, buffer, activityWindow; bool viewGroupIsWindow = false, fullScreen = false, navBarsHidden = false; int sizeAllocated = 0; - float scale = (float) Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer) diff --git a/modules/juce_opengl/native/juce_OpenGL_android.h b/modules/juce_opengl/native/juce_OpenGL_android.h index a5ac7d99bd..62a00d3d7f 100644 --- a/modules/juce_opengl/native/juce_OpenGL_android.h +++ b/modules/juce_opengl/native/juce_OpenGL_android.h @@ -147,10 +147,7 @@ public: AndroidViewGroup.addView, surfaceView.get()); // initialise the geometry of the view - auto bounds = component.getTopLevelComponent()->getLocalArea (&component, component.getLocalBounds()); - bounds *= component.getDesktopScaleFactor(); - - updateWindowPosition (bounds); + updateWindowPosition (component.localAreaToGlobal (component.getLocalBounds())); hasInitialised = true; } @@ -221,16 +218,17 @@ public: //============================================================================== void updateWindowPosition (Rectangle bounds) { - if (lastBounds != bounds) - { - auto env = getEnv(); + const auto physical = Desktop::getInstance().getDisplays().logicalToPhysical (bounds.toFloat()).toNearestInt(); - lastBounds = bounds; - auto r = bounds * Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale; + if (std::exchange (physicalBounds, physical) == physical) + return; - env->CallVoidMethod (surfaceView.get(), JuceOpenGLViewSurface.layout, - (jint) r.getX(), (jint) r.getY(), (jint) r.getRight(), (jint) r.getBottom()); - } + getEnv()->CallVoidMethod (surfaceView.get(), + JuceOpenGLViewSurface.layout, + (jint) physical.getX(), + (jint) physical.getY(), + (jint) physical.getRight(), + (jint) physical.getBottom()); } //============================================================================== @@ -401,7 +399,7 @@ private: bool hasInitialised = false; GlobalRef surfaceView; - Rectangle lastBounds; + Rectangle physicalBounds; struct SurfaceDestructor { @@ -421,15 +419,12 @@ private: GlobalRef surfaceHolderCallback; - static EGLDisplay display; - static EGLConfig config; + inline static EGLDisplay display = EGL_NO_DISPLAY; + inline static EGLConfig config; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext) }; -EGLDisplay OpenGLContext::NativeContext::display = EGL_NO_DISPLAY; -EGLDisplay OpenGLContext::NativeContext::config; - //============================================================================== bool OpenGLHelpers::isContextActive() {