diff --git a/flutter-idea/src/io/flutter/devtools/DevToolsUrl.java b/flutter-idea/src/io/flutter/devtools/DevToolsUrl.java index c89c49ee5e..4f524d0474 100644 --- a/flutter-idea/src/io/flutter/devtools/DevToolsUrl.java +++ b/flutter-idea/src/io/flutter/devtools/DevToolsUrl.java @@ -25,7 +25,6 @@ public class DevToolsUrl { public String colorHexCode; public Boolean isBright; public String widgetId; - public Float fontSize; public String hide; private final FlutterSdkVersion flutterSdkVersion; private final FlutterSdkUtil sdkUtil; @@ -45,7 +44,6 @@ public static class Builder { private String page; private Boolean embed; private String widgetId; - private Float fontSize; private String hide; private FlutterSdkVersion flutterSdkVersion; @@ -88,11 +86,6 @@ public Builder setWidgetId(String widgetId) { return this; } - public Builder setFontSize(Float fontSize) { - this.fontSize = fontSize; - return this; - } - public Builder setHide(String hide) { this.hide = hide; return this; @@ -147,7 +140,6 @@ private DevToolsUrl(Builder builder) { if (builder.embed) { this.colorHexCode = builder.devToolsUtils.getColorHexCode(); this.isBright = builder.devToolsUtils.getIsBackgroundBright(); - this.fontSize = builder.devToolsUtils.getFontSize(); } this.hide = builder.hide; this.widgetId = builder.widgetId; @@ -196,9 +188,6 @@ public String getUrlString() { } } } - if (fontSize != null) { - params.add("fontSize=" + fontSize); - } if (ideFeature != null) { params.add("ideFeature=" + ideFeature.value); } @@ -226,11 +215,4 @@ public void maybeUpdateColor() { colorHexCode = newColor; isBright = devToolsUtils.getIsBackgroundBright(); } - - public void maybeUpdateFontSize() { - final Float newFontSize = devToolsUtils.getFontSize(); - if (fontSize == null || !fontSize.equals(newFontSize)) { - fontSize = newFontSize; - } - } } diff --git a/flutter-idea/src/io/flutter/jxbrowser/EmbeddedJxBrowser.java b/flutter-idea/src/io/flutter/jxbrowser/EmbeddedJxBrowser.java index 534207fc37..a1ab1fe6f0 100644 --- a/flutter-idea/src/io/flutter/jxbrowser/EmbeddedJxBrowser.java +++ b/flutter-idea/src/io/flutter/jxbrowser/EmbeddedJxBrowser.java @@ -25,11 +25,15 @@ import io.flutter.settings.FlutterSettings; import io.flutter.utils.AsyncUtils; import io.flutter.utils.JxBrowserUtils; +import io.flutter.utils.ZoomLevelSelector; import io.flutter.view.EmbeddedBrowser; import io.flutter.view.EmbeddedTab; import io.flutter.utils.LabelInput; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import com.teamdev.jxbrowser.zoom.Zoom; +import com.teamdev.jxbrowser.zoom.ZoomLevel; +import com.intellij.ide.ui.UISettingsUtils; import javax.swing.*; import java.awt.*; @@ -43,6 +47,8 @@ class EmbeddedJxBrowserTab implements EmbeddedTab { private final Engine engine; private Browser browser; + private Zoom zoom; + private final ZoomLevelSelector zoomSelector = new ZoomLevelSelector(); private static final Logger LOG = Logger.getInstance(EmbeddedJxBrowserTab.class); public EmbeddedJxBrowserTab(Engine engine) { @@ -50,6 +56,7 @@ public EmbeddedJxBrowserTab(Engine engine) { try { this.browser = engine.newBrowser(); + this.zoom = this.browser.zoom(); this.browser.settings().enableTransparentBackground(); this.browser.on(ConsoleMessageReceived.class, event -> { final ConsoleMessage consoleMessage = event.consoleMessage(); @@ -74,6 +81,20 @@ public void close() { this.browser.close(); } + @Override + public void matchIdeZoom() { + if (this.zoom != null) { + final ZoomLevel zoomLevel = zoomSelector.getClosestZoomLevel(getIdeZoomPercent()); + this.zoom.level(zoomLevel); + } + } + + private int getIdeZoomPercent() { + final UISettingsUtils uiSettingsUtils = UISettingsUtils.getInstance(); + final float ideScale = uiSettingsUtils.getCurrentIdeScale(); + return Math.round(ideScale * 100); + } + @Override public JComponent getTabComponent(ContentManager contentManager) { // Creating Swing component for rendering web content diff --git a/flutter-idea/src/io/flutter/utils/ZoomLevelSelector.java b/flutter-idea/src/io/flutter/utils/ZoomLevelSelector.java new file mode 100644 index 0000000000..e7b85c10e5 --- /dev/null +++ b/flutter-idea/src/io/flutter/utils/ZoomLevelSelector.java @@ -0,0 +1,49 @@ +/* + * Copyright 2025 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +package io.flutter.utils; + +import com.teamdev.jxbrowser.zoom.ZoomLevel; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +import static java.util.Map.entry; + +public class ZoomLevelSelector { + @NotNull final Map zoomLevels = Map.ofEntries( + entry(25, ZoomLevel.P_25), + entry(33, ZoomLevel.P_33), + entry(50, ZoomLevel.P_50), + entry(67, ZoomLevel.P_67), + entry(75, ZoomLevel.P_75), + entry(80, ZoomLevel.P_80), + entry(90, ZoomLevel.P_90), + entry(100, ZoomLevel.P_100), + entry(110, ZoomLevel.P_110), + entry(125, ZoomLevel.P_125), + entry(150, ZoomLevel.P_150), + entry(175, ZoomLevel.P_175), + entry(200, ZoomLevel.P_200), + entry(250, ZoomLevel.P_250), + entry(300, ZoomLevel.P_300), + entry(400, ZoomLevel.P_400), + entry(500, ZoomLevel.P_500) + ); + + public @NotNull ZoomLevel getClosestZoomLevel(int zoomPercent) { + ZoomLevel closest = ZoomLevel.P_100; + int minDifference = Integer.MAX_VALUE; + + for (Map.Entry entry : zoomLevels.entrySet()) { + int currentDifference = Math.abs(zoomPercent - entry.getKey()); + if (currentDifference < minDifference) { + minDifference = currentDifference; + closest = entry.getValue(); + } + } + + return closest; + }} diff --git a/flutter-idea/src/io/flutter/view/EmbeddedBrowser.java b/flutter-idea/src/io/flutter/view/EmbeddedBrowser.java index 96649b1306..35766f6d72 100644 --- a/flutter-idea/src/io/flutter/view/EmbeddedBrowser.java +++ b/flutter-idea/src/io/flutter/view/EmbeddedBrowser.java @@ -140,6 +140,7 @@ public void openPanel(ToolWindow toolWindow, String tabName, DevToolsUrl devTool tab.content.setIcon(FlutterIcons.Phone); tab.contentManager.addContent(tab.content); tab.contentManager.setSelectedContent(tab.content, true); + tab.embeddedTab.matchIdeZoom(); }); } @@ -262,8 +263,8 @@ public void refresh(String toolWindowId) { tab.devToolsUrlFuture.thenAccept(devToolsUrl -> { if (devToolsUrl == null) return; devToolsUrl.maybeUpdateColor(); - devToolsUrl.maybeUpdateFontSize(); tab.embeddedTab.loadUrl(devToolsUrl.getUrlString()); + tab.embeddedTab.matchIdeZoom(); }); }); } @@ -290,6 +291,7 @@ private void updateUrlAndReload(Function newDevToolsUr return; } tab.embeddedTab.loadUrl(devToolsUrl.getUrlString()); + tab.embeddedTab.matchIdeZoom(); }); }); }); diff --git a/flutter-idea/src/io/flutter/view/EmbeddedJcefBrowser.java b/flutter-idea/src/io/flutter/view/EmbeddedJcefBrowser.java index afc6835114..bf56b1fbb7 100644 --- a/flutter-idea/src/io/flutter/view/EmbeddedJcefBrowser.java +++ b/flutter-idea/src/io/flutter/view/EmbeddedJcefBrowser.java @@ -33,6 +33,11 @@ public void close() { } + @Override + public void matchIdeZoom() { + + } + @Override public JComponent getTabComponent(ContentManager contentManager) { browser.getComponent().setPreferredSize(new Dimension(contentManager.getComponent().getWidth(), contentManager.getComponent().getHeight())); diff --git a/flutter-idea/src/io/flutter/view/EmbeddedTab.java b/flutter-idea/src/io/flutter/view/EmbeddedTab.java index 4bc99ad7d7..b9d16014c4 100644 --- a/flutter-idea/src/io/flutter/view/EmbeddedTab.java +++ b/flutter-idea/src/io/flutter/view/EmbeddedTab.java @@ -14,5 +14,7 @@ public interface EmbeddedTab { void close(); + void matchIdeZoom(); + JComponent getTabComponent(ContentManager contentManager); } diff --git a/flutter-idea/testSrc/unit/io/flutter/FlutterUtilsTest.java b/flutter-idea/testSrc/unit/io/flutter/FlutterUtilsTest.java index e056d1607f..6a0a50177f 100644 --- a/flutter-idea/testSrc/unit/io/flutter/FlutterUtilsTest.java +++ b/flutter-idea/testSrc/unit/io/flutter/FlutterUtilsTest.java @@ -5,11 +5,14 @@ */ package io.flutter; +import com.teamdev.jxbrowser.zoom.ZoomLevel; +import io.flutter.utils.ZoomLevelSelector; import org.junit.Test; import static io.flutter.FlutterUtils.isValidDartIdentifier; import static io.flutter.FlutterUtils.isValidPackageName; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; public class FlutterUtilsTest { @@ -39,4 +42,19 @@ public void validPackageNames() { assertFalse("expected " + name + " to be invalid", isValidPackageName(name)); } } + + @Test + public void zoomLevelSelector() { + final ZoomLevelSelector zoomLevelSelector = new ZoomLevelSelector(); + assertSame(zoomLevelSelector.getClosestZoomLevel(-70), ZoomLevel.P_25); + assertSame(zoomLevelSelector.getClosestZoomLevel(-10), ZoomLevel.P_25); + assertSame(zoomLevelSelector.getClosestZoomLevel(0), ZoomLevel.P_25); + assertSame(zoomLevelSelector.getClosestZoomLevel(1), ZoomLevel.P_25); + assertSame(zoomLevelSelector.getClosestZoomLevel(20), ZoomLevel.P_25); + assertSame(zoomLevelSelector.getClosestZoomLevel(28), ZoomLevel.P_25); + assertSame(zoomLevelSelector.getClosestZoomLevel(35), ZoomLevel.P_33); + assertSame(zoomLevelSelector.getClosestZoomLevel(222), ZoomLevel.P_200); + assertSame(zoomLevelSelector.getClosestZoomLevel(226), ZoomLevel.P_250); + assertSame(zoomLevelSelector.getClosestZoomLevel(700), ZoomLevel.P_500); + } } diff --git a/flutter-idea/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java b/flutter-idea/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java index 52bdfc8ab1..1701ef49cf 100644 --- a/flutter-idea/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java +++ b/flutter-idea/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java @@ -34,7 +34,6 @@ public void testGetUrlStringWithoutColor() { final DevToolsUtils noColorUtils = mock(DevToolsUtils.class); when(noColorUtils.getColorHexCode()).thenReturn(null); when(noColorUtils.getIsBackgroundBright()).thenReturn(null); - when(noColorUtils.getFontSize()).thenReturn(null); assertEquals( "http://127.0.0.1:9100/timeline?ide=IntelliJ-IDEA&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", @@ -163,7 +162,6 @@ public final void testGetUrlStringWithColor() { final DevToolsUtils lightUtils = mock(DevToolsUtils.class); when(lightUtils.getColorHexCode()).thenReturn("ffffff"); when(lightUtils.getIsBackgroundBright()).thenReturn(true); - when(lightUtils.getFontSize()).thenReturn(null); assertEquals( "http://127.0.0.1:9100/timeline?ide=IntelliJ-IDEA&backgroundColor=ffffff&theme=light&embed=true&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", @@ -181,29 +179,11 @@ public final void testGetUrlStringWithColor() { .getUrlString() ); - when(lightUtils.getFontSize()).thenReturn(12f); - assertEquals( - "http://127.0.0.1:9100/timeline?ide=IntelliJ-IDEA&backgroundColor=ffffff&theme=light&embed=true&fontSize=12.0&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - new DevToolsUrl.Builder() - .setDevToolsHost(devtoolsHost) - .setDevToolsPort(devtoolsPort) - .setVmServiceUri(serviceProtocolUri) - .setEmbed(true) - .setPage(page) - .setFlutterSdkVersion(newVersion) - .setWorkspaceCache(notBazelWorkspaceCache) - .setFlutterSdkUtil(mockSdkUtil) - .setDevToolsUtils(lightUtils) - .build() - .getUrlString() - ); - when(mockSdkUtil.getFlutterHostEnvValue()).thenReturn("Android-Studio"); final DevToolsUtils darkUtils = mock(DevToolsUtils.class); when(darkUtils.getColorHexCode()).thenReturn("3c3f41"); when(darkUtils.getIsBackgroundBright()).thenReturn(false); - when(darkUtils.getFontSize()).thenReturn(null); assertEquals( "http://127.0.0.1:9100/timeline?ide=Android-Studio&backgroundColor=3c3f41&theme=dark&embed=true&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F",