Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 1.6.2 - 2026-07-26

### Fixed
- The web page now renders crisply on HiDPI/Retina displays and no longer looks mis-scaled or changes size with Minecraft's GUI Scale setting.

## 1.6.1 - 2026-07-26

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx4G
org.gradle.parallel=true
dev.kikugie.stonecutter.hard_mode=true

mod_version=1.6.1
mod_version=1.6.2
maven_group=land.webgui
archives_base_name=webgui

Expand Down
42 changes: 23 additions & 19 deletions src/main/java/land/webgui/WebHudOverlay.java
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ static void onHudBrowserLoadFinished(MCEFBrowser browser) {
}
if (WebSession.mode() == WebSession.Mode.HUD_OVERLAY && browser == WebSession.browser()) {
hudPageReady = true;
WebViewLayout.applyZoom(browser);
}
}

Expand Down Expand Up @@ -478,26 +479,22 @@ public static boolean containsMouse(double mouseX, double mouseY, MinecraftClien

//? if fabric {
public static int toBrowserLocalX(double mouseX, MinecraftClient client) {
int sw = client.getWindow().getScaledWidth();
//? } else {
/*public static int toBrowserLocalX(double mouseX, Minecraft client) {*/
/*public static int toBrowserLocalX(double mouseX, Minecraft client) {
int sw = client.getWindow().getGuiScaledWidth();*/
//? }
//? if fabric {
return (int) (mouseX * client.getWindow().getScaleFactor());
//? } else {
/*return (int) (mouseX * client.getWindow().getGuiScale());*/
//? }
return (int) Math.round(mouseX * browserViewSize(client)[0] / (double) Math.max(1, sw));
}

//? if fabric {
public static int toBrowserLocalY(double mouseY, MinecraftClient client) {
int sh = client.getWindow().getScaledHeight();
//? } else {
/*public static int toBrowserLocalY(double mouseY, Minecraft client) {*/
/*public static int toBrowserLocalY(double mouseY, Minecraft client) {
int sh = client.getWindow().getGuiScaledHeight();*/
//? }
//? if fabric {
return (int) (mouseY * client.getWindow().getScaleFactor());
//? } else {
/*return (int) (mouseY * client.getWindow().getGuiScale());*/
//? }
return (int) Math.round(mouseY * browserViewSize(client)[1] / (double) Math.max(1, sh));
}

//? if fabric {
Expand All @@ -509,20 +506,27 @@ static void resizeBrowser(MinecraftClient client) {
if (browser == null) {
return;
}
//? if fabric {
int pxW = client.getWindow().getWidth();
int pxH = client.getWindow().getHeight();
//? } else {
/*int pxW = client.getWindow().getWidth();
int pxH = client.getWindow().getHeight();*/
//? }
int[] size = browserViewSize(client);
int pxW = size[0];
int pxH = size[1];
if (pxW != lastPixelW || pxH != lastPixelH) {
browser.resize(pxW, pxH);
WebViewLayout.applyZoom(browser);
lastPixelW = pxW;
lastPixelH = pxH;
}
}

// Browser view size = physical framebuffer px; page zoom keeps the CSS viewport logical.
//? if fabric {
private static int[] browserViewSize(MinecraftClient client) {
//? } else {
/*private static int[] browserViewSize(Minecraft client) {*/
//? }
var window = client.getWindow();
return WebViewLayout.browserSize(window.getWidth(), window.getHeight());
}

//? if fabric {
private static void notifyMcefMissing(MinecraftClient client) {
if (client.player != null) {
Expand Down
53 changes: 53 additions & 0 deletions src/main/java/land/webgui/WebViewLayout.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package land.webgui;

import com.cinemamod.mcef.MCEFBrowser;
import org.lwjgl.glfw.GLFW;

/**
* Sizing/scale helpers for the embedded browser. The browser view is the physical framebuffer size
* (so its texture draws 1:1 → crisp on HiDPI), and CEF page zoom scales the content up by the OS
* content scale so the page's CSS viewport stays logical and independent of Minecraft's GUI Scale.
* Uses only the public {@link MCEFBrowser#setZoomLevel} API — no device_scale_factor, no reflection.
*/
final class WebViewLayout {
private WebViewLayout() {}

/** OS content scale of the current window (e.g. 2 on a Retina display), or 1 if unknown. */
static float contentScale() {
long handle = GLFW.glfwGetCurrentContext();
if (handle == 0L) {
return 1f;
}
float[] sx = new float[1];
float[] sy = new float[1];
GLFW.glfwGetWindowContentScale(handle, sx, sy);
return sx[0] > 0f ? sx[0] : 1f;
}

/** Browser view size = physical framebuffer pixels, so the OSR texture is drawn 1:1 (crisp). */
static int[] browserSize(int framebufferWidth, int framebufferHeight) {
return new int[] {Math.max(1, framebufferWidth), Math.max(1, framebufferHeight)};
}

/**
* CEF zoom level that scales content by the content scale: {@code zoomFactor = 1.2^level}, so
* {@code level = log(scale) / log(1.2)}. Result: CSS viewport = framebuffer / scale (logical),
* rendered at framebuffer resolution. 0 when no scaling is needed.
*/
static double zoomLevel() {
float scale = contentScale();
return scale > 1f ? Math.log(scale) / Math.log(1.2) : 0.0;
}

/** Applies the content-scale zoom. CEF may reset zoom on navigation, so call after load too. */
static void applyZoom(MCEFBrowser browser) {
if (browser == null) {
return;
}
try {
browser.setZoomLevel(zoomLevel());
} catch (Throwable t) {
WebGUIMod.LOGGER.warn("[WebGUI] setZoomLevel failed: {}", t.toString());
}
}
}
31 changes: 15 additions & 16 deletions src/main/java/land/webgui/WebViewScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,32 +105,30 @@ private boolean isInBrowserBounds(double x, double y) {
return x >= 0 && y >= 0 && x < this.width && y < this.height;
}

private int browserLocalMouseX(double x) {
// Browser view size in logical window points, independent of the GUI Scale setting.
private int[] browserViewSize() {
//? if fabric {
return (int) (x * this.client.getWindow().getScaleFactor());
var window = this.client.getWindow();
//? } else {
/*return (int) (x * this.minecraft.getWindow().getGuiScale());*/
/*var window = this.minecraft.getWindow();*/
//? }
return WebViewLayout.browserSize(window.getWidth(), window.getHeight());
}

private int browserLocalMouseX(double x) {
return (int) Math.round(x * browserViewSize()[0] / (double) getBrowserWidth());
}

private int browserLocalMouseY(double y) {
//? if fabric {
return (int) (y * this.client.getWindow().getScaleFactor());
//? } else {
/*return (int) (y * this.minecraft.getWindow().getGuiScale());*/
//? }
return (int) Math.round(y * browserViewSize()[1] / (double) getBrowserHeight());
}

private void resizeBrowser() {
//? if fabric {
if (browser != null && this.client != null) {
browser.resize(this.client.getWindow().getWidth(), this.client.getWindow().getHeight());
if (browser != null) {
int[] size = browserViewSize();
browser.resize(size[0], size[1]);
WebViewLayout.applyZoom(browser);
}
//? } else {
/*if (browser != null && this.minecraft != null) {
browser.resize(this.minecraft.getWindow().getWidth(), this.minecraft.getWindow().getHeight());
}*/
//? }
}

//? if >=1.21.5 {
Expand Down Expand Up @@ -194,6 +192,7 @@ static void onGuiBrowserLoadFinished(MCEFBrowser browser) {
}
if (WebSession.mode() == WebSession.Mode.GUI_SCREEN && browser == WebSession.browser()) {
guiPageReady = true;
WebViewLayout.applyZoom(browser);
}
}

Expand Down
Loading