Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
a3343a1
js port: make the semantic DOM overlay incremental
shai-almog Aug 15, 2026
95b6921
js port: render text as real DOM above the canvas
shai-almog Aug 15, 2026
a90cfd5
js port: read browser and OS state on the main thread, not in the worker
shai-almog Aug 15, 2026
097fca0
js port: assert the overlay layers directly, and document them
shai-almog Aug 15, 2026
7cfd4dc
js port: render at the display's real pixel ratio
shai-almog Aug 16, 2026
ac72ca7
js port: give the native editor the attributes browsers act on
shai-almog Aug 16, 2026
9ffdd8b
js port: capture the composited page for screenshot goldens
shai-almog Aug 16, 2026
e157713
js port: address review on the text layer and screenshot capture
shai-almog Aug 16, 2026
94f5e72
js port: return the composited capture instead of writing it
shai-almog Aug 16, 2026
7fcccf5
js port: rebaseline screenshot goldens for device-pixel rendering and…
shai-almog Aug 16, 2026
f210351
js port: bound the composited capture, and four more review fixes
shai-almog Aug 16, 2026
175a9b2
js port: restore animation settling, and five more review fixes
shai-almog Aug 16, 2026
1394f38
js port: return text to the canvas once the app reads pixels back
shai-almog Aug 16, 2026
61b39a6
js port: rebaseline goldens against the settled rendering
shai-almog Aug 16, 2026
9752877
js port: restore the capture settle, and two more review fixes
shai-almog Aug 16, 2026
3b29e62
js port: three more review fixes
shai-almog Aug 16, 2026
4c406f3
js port: do not force a paint from inside the screenshot read
shai-almog Aug 16, 2026
f69e25d
js port: finish the stacking, history and screenshot review items
shai-almog Aug 16, 2026
40b025f
js port: do not traverse history twice, and restore find after a read…
shai-almog Aug 16, 2026
5ff35df
js port: only assert history growth when the app navigated
shai-almog Aug 16, 2026
0d39c70
js port: refresh semantics after a readback, and follow framework focus
shai-almog Aug 16, 2026
42f0bc0
js port: clear cached focus on prune, and keep Forward in step
shai-almog Aug 16, 2026
0a802b1
js port: check ancestor visibility, and re-resolve styles on scheme c…
shai-almog Aug 16, 2026
a4e0139
js port: never expose an obscured field's content, and name dialogs
shai-almog Aug 16, 2026
66ca7f9
js port: consume every skipped entry, and follow a changing pixel ratio
shai-almog Aug 16, 2026
22a2684
js port: four review fixes around pixel ratio, history and obscured l…
shai-almog Aug 16, 2026
74721c1
js port: stop semantic keys dispatching twice, and project collection…
shai-almog Aug 16, 2026
44142a5
js port: keep custom-action buttons from triggering their parent
shai-almog Aug 16, 2026
b7eb11e
js port: gate arrow keys, fix nested bounds, expose scroll actions
shai-almog Aug 16, 2026
b7f6377
js port: recognise inferred labels properly, rebuild density on a rat…
shai-almog Aug 16, 2026
8fa4825
js port: one popstate listener, and keep text through clipped repaints
shai-almog Aug 16, 2026
b8b302f
js port: correct a stale note about the screenshot goldens
shai-almog Aug 16, 2026
6482d61
js port: compare clips in absolute coordinates, and carry Back outwards
shai-almog Aug 16, 2026
8d4ca3b
js port: take the navigation direction from the framework
shai-almog Aug 16, 2026
767fda3
js port: carry direction on the form, and refresh cached forms on a s…
shai-almog Aug 16, 2026
4968903
js port: keep run identity through clipped paints, focus attached nod…
shai-almog Aug 16, 2026
2878afd
js port: keep hit testing intact with peers, and mirror every visible…
shai-almog Aug 16, 2026
abbf917
js port: do not lose a first clipped paint, and unwind the whole history
shai-almog Aug 16, 2026
7f9c513
js port: reset the derived PPI with the density, and count entries un…
shai-almog Aug 16, 2026
f5e9e57
js port: reconcile clipped runs, and keep labels in the semantic tree
shai-almog Aug 16, 2026
b7c1cfa
js port: match clipped runs by position first, and honour multi-entry…
shai-almog Aug 16, 2026
5a7b440
js port: take multi-entry back steps one at a time
shai-almog Aug 16, 2026
d566687
js port: hold popstate ownership until the back transition lands
shai-almog Aug 16, 2026
52fa0ce
js port: drop the rest of a history jump once a step is refused
shai-almog Aug 16, 2026
753c60d
js port: publish a typing field's contents as its accessible value
shai-almog Aug 16, 2026
1c6a8d8
js port: claim runs per paint, and hold action controls outside the w…
shai-almog Aug 17, 2026
56de0a1
core: keep a dialog's title when its theme is refreshed
shai-almog Aug 17, 2026
051ebdc
js port: leave the document when a form has nowhere to go back to
shai-almog Aug 17, 2026
907db72
js port: return the whole traversal when a back step is refused
shai-almog Aug 17, 2026
474afe3
js port: draw down a jump by the forms each back command leaves
shai-almog Aug 17, 2026
964260d
js port: stamp history entries as this port's own
shai-almog Aug 17, 2026
7490151
js port: keep font sizes with the density, and name the username field
shai-almog Aug 17, 2026
7b3be74
js port: join a second Back to the walk in flight, and follow a renam…
shai-almog Aug 17, 2026
26dc453
js port: give up on a traversal the browser never made
shai-almog Aug 17, 2026
9013a2f
js port: leave a host page's own history entries alone
shai-almog Aug 17, 2026
a76686d
js port: take the screenshot on a frame boundary
shai-almog Aug 17, 2026
75096ff
js port: keep decorated text whole on the canvas
shai-almog Aug 17, 2026
2f55aeb
js port: give text back to the canvas when the canvas draws over it
shai-almog Aug 17, 2026
2cc6f85
js port: measure what a promoted run actually covers
shai-almog Aug 17, 2026
eaf7fa0
js port: match a clipped run by both coordinates, and follow the tran…
shai-almog Aug 17, 2026
bdad398
js port: repaint the form when the text layer hides, and press toggle…
shai-almog Aug 17, 2026
3c2822c
js port: decide coverage by which component is drawing
shai-almog Aug 17, 2026
c208a0a
core: queue a form's navigation directions instead of keeping one
shai-almog Aug 17, 2026
5543dd3
js port: rebaseline the goldens the layering fixes moved
shai-almog Aug 17, 2026
e268ed1
js port: wait out the pauses between paints before capturing
shai-almog Aug 17, 2026
1ce20ec
core: use the import the file already has
shai-almog Aug 17, 2026
5bd335d
js port: keep the popstate handler behind the lifecycle coordinator
shai-almog Aug 17, 2026
1ed83a8
js port: record the occlusion rule in STATUS.md
shai-almog Aug 17, 2026
61556f6
js port: outlast the pauses between cell paints before capturing
shai-almog Aug 17, 2026
04d7034
js port: hold a blitted image until its batch has been shipped
shai-almog Aug 17, 2026
07d8a32
Answer eleven review findings across the overlay, the port and the core
shai-almog Aug 17, 2026
5f0de7d
js port: count an ancestor drawing over its children as coverage
shai-almog Aug 17, 2026
217b5f7
js port: keep a clip only when the repaint region is what narrowed it
shai-almog Aug 17, 2026
79212f9
js port: wait for Back on the clock, and keep a font's identity still
shai-almog Aug 17, 2026
51a2b60
js port: read what a Back owes before the command runs
shai-almog Aug 17, 2026
fea96b4
js port: ask a shape what it covers, not its bounding box
shai-almog Aug 17, 2026
6e39776
js port: ask a shape whether it meets the text at all
shai-almog Aug 17, 2026
baa9858
js port: ask a filled arc about its sector, not its bounding box
shai-almog Aug 17, 2026
7cdb028
js port: finish asking every draw what it really covers
shai-almog Aug 17, 2026
b596959
js port: clip before projecting, respect winding, and queue our own t…
shai-almog Aug 17, 2026
1f88a1b
Restore two goldens the narrower coverage rule brought back
shai-almog Aug 17, 2026
5eb0935
Say that leaving a menu goes backwards, and hold semantics on the clock
shai-almog Aug 17, 2026
bed8212
js port: trace a rounded rectangle once round its perimeter
shai-almog Aug 18, 2026
8c08ddc
js port: leave a run's place in the order alone during a partial repaint
shai-almog Aug 18, 2026
0cd49d3
js port: stop asking a document that refuses history, and queue captures
shai-almog Aug 18, 2026
c8208d4
Report stroked draws as coverage, and let a folding menu go first
shai-almog Aug 18, 2026
38de50e
js port: report clears and lens draws as coverage
shai-almog Aug 18, 2026
8d26cc6
js port: glass and clears count too, and a disabled node acts on nothing
shai-almog Aug 18, 2026
11e72a9
js port: a disabled node offers no custom actions either
shai-almog Aug 18, 2026
c6bb79e
Rebaseline two charts whose labels now rasterize on the canvas
shai-almog Aug 18, 2026
b933516
Keep the title area's theme UIID, and never publish invisible text
shai-almog Aug 18, 2026
afb458c
js port: build a round-rect outline from the radius that is drawn
shai-almog Aug 18, 2026
75199a4
js port: record why the text layer takes no pointer events
shai-almog Aug 18, 2026
6e4fc3a
js port: a backdrop effect counts whatever the alpha says
shai-almog Aug 18, 2026
7dddd2a
core: keep every queued navigation direction
shai-almog Aug 18, 2026
04e6f2d
js port: walk a shape's curves instead of its control points
shai-almog Aug 18, 2026
5d81c77
js port: sweep a filled arc the short way round
shai-almog Aug 18, 2026
825e997
js port: rebaseline graphics-fill-arc on the corrected sweep
shai-almog Aug 18, 2026
a793ab7
js port: let a shape clip protect the text it covers
shai-almog Aug 18, 2026
9a0c209
docs: record what the clip contributes to text coverage
shai-almog Aug 18, 2026
e29abd7
js port: claim the entry a reload lands on as the session root
shai-almog Aug 18, 2026
61f5dcb
js port: give a screen reader a way to type into a field
shai-almog Aug 18, 2026
28205f2
js port: keep the draw's shape when text coverage crosses a transform
shai-almog Aug 18, 2026
fe86f01
js port: follow a field between masked and revealed
shai-almog Aug 18, 2026
6fa533e
js port: drop text a partial repaint stopped drawing
shai-almog Aug 18, 2026
3a65503
js port: edit a multiline field through a control that holds lines
shai-almog Aug 18, 2026
65e5898
js port: do not push an entry for the form already on screen
shai-almog Aug 18, 2026
bbb85f6
tests: count a multiline field's control in the overlay check
shai-almog Aug 18, 2026
898aadc
js port: decide listbox and option together
shai-almog Aug 18, 2026
38ad81c
js port: ask the draw and the clip only about text the clip can reach
shai-almog Aug 18, 2026
e5e7190
js port: put action controls behind the form they act on
shai-almog Aug 18, 2026
30fafde
js port: let every waiting capture have its frame
shai-almog Aug 18, 2026
437089f
js port: compare a clip and a draw where the canvas applies them
shai-almog Aug 18, 2026
c969097
js port: stop closing outlines the draw left open
shai-almog Aug 18, 2026
7ddd6b0
js port: do not leave a password in the document after the edit
shai-almog Aug 18, 2026
9d61d43
js port: read a foreign history id instead of overwriting it
shai-almog Aug 18, 2026
f3942f2
js port: read the screen back once the painting has stopped
shai-almog Aug 18, 2026
5360177
js port: hold a SET_TEXT control to the field's own limit
shai-almog Aug 18, 2026
bff5396
js port: keep the length limit current for every control
shai-almog Aug 18, 2026
da70c05
js port: sweep a radial gradient the short way, and count it whatever…
shai-almog Aug 19, 2026
a5cf094
js port: count an opaque blit, and stop counting a sweep of nothing
shai-almog Aug 19, 2026
691c44f
js port: rebaseline graphics-draw-gradient on the corrected sweep
shai-almog Aug 19, 2026
54459a3
js port: read popstate state as whatever the page put there
shai-almog Aug 19, 2026
eb61786
js port: configure a set-text control from the field constraints
shai-almog Aug 19, 2026
454fafe
js port: give an edited field one tab stop, not two
shai-almog Aug 19, 2026
1196351
js port: tell the framework when focus lands on an editing control
shai-almog Aug 19, 2026
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
48 changes: 48 additions & 0 deletions CodenameOne/src/com/codename1/ui/Dialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,54 @@ public void removeComponent(Component cmp) {
dialogContentPane.removeComponent(cmp);
}

/// Refreshing the theme reinstalls the menu bar, and installing it moves the form's title
/// component into the title area. A dialog's title component is its own title label, and a
/// dialog keeps the form title area hidden -- so without putting the label back where it
/// belongs, refreshing the theme loses the dialog's title altogether, along with the space
/// it occupied in the centered-title layout.
///
/// {@inheritDoc}
@Override
public void refreshTheme(boolean merge) {
super.refreshTheme(merge);
restoreDisplacedTitle();
}

/// Puts the title label back where this dialog's layout wants it, and touches nothing else.
///
/// Rebuilding the whole layout would remove and re-add the content pane, which deinitializes
/// that subtree -- taking the form's focus with it when the focused component is in there,
/// and closing an editor the user is typing in. Only the label moved, so only the label is
/// moved back.
private void restoreDisplacedTitle() {
Container root = super.getContentPane();
Container target = titleCentered ? centeredTitleArea : root;
if (target == null) {
updateTitleLayout();
revalidate();
return;
}
if (titleCentered && centeredTitleArea != null) {
// The area's UIID comes from a theme constant, and a refresh is exactly when that
// constant can have changed. Restoring the label without it would leave a centered
// dialog wearing the previous theme's title styling.
centeredTitleArea.setUIID(getUIManager().getThemeConstant(
"dlgCenteredTitleUIID", "Container"));
}
if (dialogTitle.getParent() == target) { //NOPMD CompareObjectsWithEquals
return;
}
if (dialogTitle.getParent() != null) {
dialogTitle.remove();
}
if (titleCentered) {
target.addComponent(BorderLayout.CENTER, dialogTitle);
Comment thread
shai-almog marked this conversation as resolved.
} else {
target.addComponent(BorderLayout.NORTH, dialogTitle);
}
revalidate();
}

/// {@inheritDoc}
@Override
public Label getTitleComponent() {
Expand Down
23 changes: 22 additions & 1 deletion CodenameOne/src/com/codename1/ui/Display.java
Original file line number Diff line number Diff line change
Expand Up @@ -1622,12 +1622,14 @@ void setCurrent(final Form newForm, boolean reverse) {
if (edt == null) {
throw new IllegalStateException("Initialize must be invoked before setCurrent!");
}

if (!isEdt()) {
// when not running callSerially executes synchronously and would recurse here forever (#4811)
if (!codenameOneRunning) {
throw new IllegalStateException("Display.setCurrent must be invoked after Codename One has started running. Call it from start() or via callSerially.");
}
// The direction is not recorded here: this call comes back round on the EDT and
// records it there. Doing it in both places would leave one entry behind for a
// later navigation to the same form to take.
callSerially(new RunnableWrapper(newForm, null, reverse));
return;
}
Expand Down Expand Up @@ -1657,13 +1659,20 @@ void setCurrent(final Form newForm, boolean reverse) {
case SHOW_DURING_EDIT_IGNORE:
return;
case SHOW_DURING_EDIT_SET_AS_NEXT:
newForm.setShownWithReverse(reverse);
impl.setCurrentForm(newForm);
return;
default:
break;
}
}

// Recorded once the call is known to be going through: on the EDT, with the form
// changing, and past the cases that decline to show anything while text is being
// edited. Recording it any earlier would queue a direction that no arrival takes, and a
// later navigation to the same form would take that stale one instead of its own.
newForm.setShownWithReverse(reverse);

if (current != null) {
if (current.isInitialized()) {
current.deinitializeImpl();
Expand Down Expand Up @@ -1713,6 +1722,18 @@ void setCurrent(final Form newForm, boolean reverse) {
}
}
current = current.getPreviousForm();
if (current != null) {
// Coming out of a menu back to the form underneath it, which is a backward
// move: without saying so, this arrival takes whatever direction that form
// has left over and a port that keeps browser history in step reads it as a
// step forward, pushing an entry for a form that was already behind.
//
// At the head of the queue, because this arrival comes first: when the form
// being revealed is also the one being shown, its own direction is already
// waiting, and appending would have this restoration take that one and leave
// this one for the show.
current.insertShownWithReverse(true);
Comment thread
shai-almog marked this conversation as resolved.
}
impl.setCurrentForm(current);
}

Expand Down
46 changes: 46 additions & 0 deletions CodenameOne/src/com/codename1/ui/Form.java
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,52 @@ Form getPreviousForm() {
return previousForm;
}

/// Directions of the displays asked for on this form that have not arrived yet, oldest
/// first. A transition defers a form change, so two navigations to the same form can be in
/// flight at once -- showBack() to it, then show() while the first is still animating -- and
/// a single field would give both arrivals the direction of the later one.
private ArrayList<Boolean> pendingReverse;

/// The direction of the last arrival, for a form change with nothing queued behind it.
private boolean lastShownWithReverse;

void setShownWithReverse(boolean value) {
if (pendingReverse == null) {
pendingReverse = new ArrayList<Boolean>();
}
// Every entry is a display that is going to arrive, so none of them is dropped: a
// handful of shows and showBacks can be in flight at once when each is waiting on a
// transition, and clearing the queue to make room would hand the first arrival the last
// caller's direction. A display that changes nothing -- showing the form already up --
// returns before it records anything, so nothing accumulates here unspent.
//
// The bound is a leak guard rather than a policy: a hundred displays of one form waiting
// at once is not navigation, it is something stuck.
if (pendingReverse.size() >= 100) {
pendingReverse.remove(0);
}
pendingReverse.add(Boolean.valueOf(value));
}

/// Puts a direction at the head of the queue, for a form change that happens before
/// anything already waiting -- a menu folding away to reveal this form, which arrives before
/// the show that asked for it.
void insertShownWithReverse(boolean value) {
if (pendingReverse == null) {
pendingReverse = new ArrayList<Boolean>();
}
pendingReverse.add(0, Boolean.valueOf(value));
}

/// Takes the direction belonging to the form change that is arriving now.
boolean consumeShownWithReverse() {
if (pendingReverse == null || pendingReverse.isEmpty()) {
return lastShownWithReverse;
}
lastShownWithReverse = pendingReverse.remove(0).booleanValue();
return lastShownWithReverse;
}

void setPreviousForm(Form previousForm) {
this.previousForm = previousForm;
}
Expand Down
102 changes: 102 additions & 0 deletions Ports/JavaScriptPort/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,108 @@ routing.
This document is the handoff for whoever picks up the branch next. Read it
before you re-attempt switching initializr over.

Web-native overlay layer
------------------------

The port renders to a canvas, but text, semantics and OS state no longer come
from it. Two DOM layers sit above the canvas, which is itself marked
`role=presentation` / `aria-hidden`:

- `#cn1-text-layer` (`JavaScriptTextLayer`) carries the **visible text**.
`BufferedGraphics.drawString` -- the display graphics -- hands each run to the
layer instead of the canvas, so the text on screen is real DOM text that can be
selected, found with the browser's find-in-page, and rasterized by the browser
rather than by canvas. Codename One remains the sole layout authority: a run
arrives already broken and placed, so it is emitted as one `white-space:pre`
element at an absolute coordinate and the browser cannot wrap or reflow it.
Text measurement is unchanged and stays on the worker's `OffscreenCanvas`.
- `#cn1-accessibility-tree` (`JavaScriptSemanticOverlay`) carries the ARIA
projection of `AccessibilityTreeSnapshot`. It is updated incrementally --
elements are keyed by semantic node id and reused -- because the previous
rebuild-per-invalidation discarded DOM focus and text selection on every
`CHANGE_BOUNDS`, which is raised by every `setX/setY/setWidth/setHeight`.

The layer takes no pointer events: the canvas owns hit testing, so a drag across
a label does not start a native selection. Find-in-page, the browser's own text
handling and assistive technology all reach the text; pointer selection would
mean teaching the port's input path to tell a selection drag from an application
drag, which is a change to input rather than to this layer.

Text that stays on the canvas, by design:

- offscreen targets (transition buffers, `paintLock`, `ComponentImage`,
`Display.screenshot`) -- they use plain `HTML5Graphics`, so the gate is
structural rather than a check;
- cell renderers, which are one component instance stamped at N positions and so
cannot key a pooled element per row;
- anything outside the displayed form, because the layer sits above the canvas as
a whole and nothing painted afterwards can occlude it (a modal dialog paints
the form beneath it as its own backdrop);
- decorated runs -- underline, strike-through, overline -- whose lines are drawn
after the glyphs and over them, which a promoted glyph would cover;
- shape clips and non-identity transforms;
- anything a later canvas draw covers. The layer is above the canvas as a whole,
so an image, fill or shape drawn over a promoted run cannot hide it the way it
would have hidden canvas text. Such a run is put back on the canvas and its
component stays there -- a sheet's scrim, a tab bar's composited lens, a
clipped rotation over a title. Who is drawing decides: a component painting its
own background, or a container painting behind children it is about to paint,
covers text it draws again a moment later and hides nothing. What the draw
reaches decides too: an empty clip or a fully transparent one reaches nothing,
the report is clipped to the graphics clip -- to the clip's own outline when it
is a shape, since text the clip protects is not covered by a draw it culls --
and a shape, polygon, arc, radial gradient or rounded rectangle is asked
whether its outline meets the glyphs rather than whether its bounding rectangle
does. Curves are walked rather than replaced by their control points.

Bitmap fonts need no exclusion: `Graphics.drawString` renders a `CustomFont`
itself and never reaches the implementation.

**Consequence for the screenshot suite:** every test in the suite reads the screen
back to capture it, and a pixel read returns text to the canvas for good -- the
two representations cannot both be authoritative, and an application that reads
pixels is saying which one it needs. The goldens are therefore canvas-text at the
display's real pixel ratio, and have been rebaselined from a CI run. The DOM
layer is covered by `scripts/verify-javascript-web-overlay.mjs`, which asserts it
directly instead of through pixels.

Known gaps in this area:

- An editable field is reached through a SET_TEXT control in the actions region rather
than by typing into the semantic node itself, which is a div over a canvas. A native
input is still what appears once editing starts.
- Drag-selection is not enabled. The layer takes no pointer events so the canvas
keeps hit testing; find-in-page and assistive technology do not need hit
testing, but selection does. Enabling it requires the pointer-routing rework.
- Vertical placement uses `fontHeight()` as the line box, which matches Codename
One's own layout metric but is approximate against the browser's font metrics
to about a pixel. A text-parity harness comparing `getBoundingClientRect()`
against the Codename One width/position is the way to tighten this.
- Occlusion within a form is not handled; only cross-form occlusion is, along with
the glass pane, a dragged component and transitions. A `Sheet`, an
`InteractionDialog`, or an opaque sibling in a `LayeredLayout` painting over a
text-bearing component will not cover its promoted text, because the layer is
above the canvas as a whole. Whether a later sibling covers an earlier one is
not known at the time the earlier one paints, so the only general answer is to
promote the covering content too -- which is the DOM renderer this deliberately
is not.

Main-thread browser state
-------------------------

Several features were written when the port ran on the main thread and silently
did nothing once it moved into a worker, because the objects they reach for do
not exist there. `history.pushState` was a `@JSBody` and threw on every form
change (the port logged that the back command would not work), and every
`matchMedia` query -- dark mode, reduced motion, forced colors, contrast,
reduced transparency -- answered `false` unconditionally. Both now go through
the host bindings so they run on the main thread; media query results are cached
and refreshed from a `change` listener.

The rule this illustrates is worth keeping in mind for any future port work:
**a `@JSBody` runs in the worker.** Anything touching `window`, `document`,
`history`, `matchMedia` or `navigator` has to go through a host binding instead.

Build
-----

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.html5.js.browser;

import com.codename1.html5.js.JSObject;

/**
* Interface for the JavaScript MediaQueryList object.
* https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList
*/
public interface MediaQueryList extends JSObject {
boolean getMatches();
String getMedia();
void addEventListener(String type, Object listener);
void removeEventListener(String type, Object listener);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,24 @@
* https://developer.mozilla.org/en-US/docs/Web/API/Window
*/
public interface Window extends JSObject {
/**
* Evaluates a CSS media query on the main thread. The worker has no matchMedia, so every
* OS-level preference -- dark mode, reduced motion, forced colors -- has to be read through
* this binding rather than from worker script.
*
* @param query the media query text
* @return the live query list, or null where the browser does not support matchMedia
*/
MediaQueryList matchMedia(String query);

/**
* The display's scale factor, read from the main thread. The worker's copy is forwarded
* once at start-up and does not follow zoom or a move between displays.
*
* @return devicePixelRatio
*/
double getDevicePixelRatio();

static Window current() {
return null; // Native implementation
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.html5.js.dom;

/**
* Interface for the JavaScript PopStateEvent object.
* https://developer.mozilla.org/en-US/docs/Web/API/PopStateEvent
*
* <p>The state is read because popstate fires for forward traversal as well as backward, and
* the two are only distinguishable by comparing the state the browser restored against the one
* currently displayed. It is typed as Object rather than String: history state is any
* structured-cloneable value, and a page that embeds this canvas may keep its router's own
* object there. Binding it as a String would put that entry through a conversion it cannot
* satisfy, when all the port needs is to see that the value is not one of its own.</p>
*/
public interface PopStateEvent extends Event {
Object getState();
}
Loading
Loading