|
| 1 | +/* |
| 2 | + * Copyright 2024 The Emscripten Authors. All rights reserved. |
| 3 | + * Emscripten is available under two separate licenses, the MIT license and the |
| 4 | + * University of Illinois/NCSA Open Source License. Both these licenses can be |
| 5 | + * found in the LICENSE file. |
| 6 | + */ |
| 7 | + |
| 8 | +#include <GLFW/glfw3.h> |
| 9 | +#include <assert.h> |
| 10 | +#include <emscripten/html5.h> |
| 11 | +#include <stdio.h> |
| 12 | + |
| 13 | +/* |
| 14 | + * History: |
| 15 | + * - This test was added after the issue #22847 was reported (November 2024). |
| 16 | + * - For historical reasons, the JavaScript GLFW implementation includes a feature: the ability to scale the canvas via CSS. |
| 17 | + * - Note that this feature is not part of GLFW as GLFW does not offer any API to scale the window. |
| 18 | + * - Being undocumented/untested, this feature was accidentally removed when HiDPI support was added (in 3.1.51 / December 2023). |
| 19 | + * - This test was added to document this feature and ensure proper behavior. |
| 20 | + * |
| 21 | + * What does this feature do? |
| 22 | + * - if there is a CSS rule that specifies the size of the canvas (ex: `#canvas { width: 100%;}`), then the canvas |
| 23 | + * will be scaled to match this value. Note that from a GLFW point of view, the size of the window remains what |
| 24 | + * gets specified in `glfwCreateWindow` and/or `glfwSetWindowSize` |
| 25 | + * - only global CSS rules apply, as setting a CSS rule on the canvas itself is removed (ex: `<canvas style="width:100%;">` is ignored) |
| 26 | + * |
| 27 | + * In HiDPI mode, (`glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE)`), this feature cannot work and as a result is disabled (because the canvas |
| 28 | + * is sized using `devicePixelRatio` as the factor and CSS is used to scale it at the desired size). |
| 29 | + */ |
| 30 | + |
| 31 | +/** |
| 32 | + * As explained above, this function adds a global CSS rule instead of setting the CSS style directly on the canvas |
| 33 | + * because it gets ignored otherwise. */ |
| 34 | +EM_JS(void, addCSSScalingRule, (), { |
| 35 | + const style = document.createElement('style'); |
| 36 | + style.appendChild(document.createTextNode("#canvas { width: 700px; height: 500px; }")); |
| 37 | + document.head.appendChild(style); |
| 38 | +}) |
| 39 | + |
| 40 | +/** |
| 41 | + * Since it is unclear in which browser/resolution this test will run we compute the actual ratio used by the test. |
| 42 | + * This has the neat effect that the test can be run manually on a HiDPI screen. |
| 43 | + */ |
| 44 | +EM_JS(double, getDevicePixelRatio, (), {return (typeof devicePixelRatio == 'number' && devicePixelRatio) || 1.0;}) |
| 45 | + |
| 46 | +/** |
| 47 | + * Checks window size and framebuffer size according to ratio */ |
| 48 | +static void checkWindowSize(GLFWwindow *window, int expectedWidth, int expectedHeight, float ratio) { |
| 49 | + // first check the window size |
| 50 | + int w, h; |
| 51 | + glfwGetWindowSize(window, &w, &h); |
| 52 | + printf("windowSize => %d == %d && %d == %d\n", w, expectedWidth, h, expectedHeight); |
| 53 | + assert(w == expectedWidth && h == expectedHeight); |
| 54 | + |
| 55 | + // second check the frame buffer size |
| 56 | + int fbw, fbh; |
| 57 | + glfwGetFramebufferSize(window, &fbw, &fbh); |
| 58 | + printf("framebufferSize => %d == %d && %d == %d\n", fbw, (int) (expectedWidth * ratio), fbh, (int) (expectedHeight * ratio)); |
| 59 | + assert(fbw == (int) (expectedWidth * ratio) && fbh == (int) (expectedHeight * ratio)); |
| 60 | +} |
| 61 | + |
| 62 | +// Create a window without HiDPI support and without CSS rule => expected sizes to match |
| 63 | +void use_case_1() { |
| 64 | + printf("Use case #1\n"); |
| 65 | + GLFWwindow* window = glfwCreateWindow(640, 480, "test_glfw3_css_scaling.c", NULL, NULL); |
| 66 | + assert(window); |
| 67 | + checkWindowSize(window, 640, 480, 1.0); |
| 68 | + double w, h; |
| 69 | + emscripten_get_element_css_size("#canvas", &w, &h); |
| 70 | + printf("CSS Size=%.0fx%.0f\n", w, h); |
| 71 | + assert(w == 640 && h == 480); |
| 72 | + glfwDestroyWindow(window); |
| 73 | +} |
| 74 | + |
| 75 | +// Create a window without HiDPI support, and with CSS rule => |
| 76 | +// the window size should match the creation size, but the CSS size should match the rule. |
| 77 | +void use_case_2() { |
| 78 | + printf("Use case #2\n"); |
| 79 | + GLFWwindow* window = glfwCreateWindow(640, 480, "test_glfw3_css_scaling.c", NULL, NULL); |
| 80 | + assert(window); |
| 81 | + checkWindowSize(window, 640, 480, 1.0); |
| 82 | + double w, h; |
| 83 | + emscripten_get_element_css_size("#canvas", &w, &h); |
| 84 | + printf("CSS Size=%.0fx%.0f\n", w, h); |
| 85 | + assert(w == 700 && h == 500); // Rule is "#canvas { width: 700px; height: 500px; }" |
| 86 | + glfwDestroyWindow(window); |
| 87 | +} |
| 88 | + |
| 89 | +// Create a window with HiDPI support, and with CSS rule => |
| 90 | +// the window size and framebuffer size should match the creation size (CSS rule is ignored) |
| 91 | +void use_case_3() { |
| 92 | + printf("Use case #3\n"); |
| 93 | + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); |
| 94 | + GLFWwindow* window = glfwCreateWindow(640, 480, "test_glfw3_css_scaling.c", NULL, NULL); |
| 95 | + assert(window); |
| 96 | + double dpr = getDevicePixelRatio(); |
| 97 | + printf("devicePixelRatio=%.0f\n", dpr); |
| 98 | + checkWindowSize(window, 640, 480, dpr); |
| 99 | + double w, h; |
| 100 | + emscripten_get_element_css_size("#canvas", &w, &h); |
| 101 | + printf("CSS Size=%.0fx%.0f\n", w, h); |
| 102 | + assert(w == 640 && h == 480); |
| 103 | + glfwDestroyWindow(window); |
| 104 | +} |
| 105 | + |
| 106 | +int main() { |
| 107 | + assert(glfwInit() == GLFW_TRUE); |
| 108 | + |
| 109 | + use_case_1(); |
| 110 | + |
| 111 | + // Add CSS rule for the following use cases |
| 112 | + addCSSScalingRule(); |
| 113 | + |
| 114 | + use_case_2(); |
| 115 | + use_case_3(); |
| 116 | + |
| 117 | + printf("All tests complete\n"); |
| 118 | + glfwTerminate(); |
| 119 | + return 0; |
| 120 | +} |
0 commit comments