diff --git a/webfx-kit/webfx-kit-javafxcontrols-emul/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java b/webfx-kit/webfx-kit-javafxcontrols-emul/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java index 4a9663a53..a64d82a3a 100644 --- a/webfx-kit/webfx-kit-javafxcontrols-emul/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java +++ b/webfx-kit/webfx-kit-javafxcontrols-emul/src/main/java/javafx/scene/control/skin/LabeledSkinBase.java @@ -543,7 +543,7 @@ private void updateWrappingWidth() { if (labeled.isWrapText() /* WebFX addition: */ && wrapWidth < noWrappingTextWidth) { // we don't set the wrapping width if not necessary due to lack of double precision in HTML (rounding to inferior pixel can cause an unwanted text wrap) // Note that the wrapping width needs to be set to zero before // getting the text's real preferred width. - double w = Math.min(text.prefWidth(-1), wrapWidth); + double w = wrapWidth; //Math.min(text.prefWidth(-1), wrapWidth); text.setWrappingWidth(w); } else text.setWrappingWidth(0); @@ -691,17 +691,14 @@ private double computeMinLabeledPartWidth(double height, double topInset, double rightInset + rightLabelPadding(); } - private double computeTextWidth(Font font, String text, double wrappingWidth) { + private double computeTextWidth(Font font, String text, double wrappingWidth) { // Note: always called with wrappingWidth = 0 for some reason //return Utils.computeTextWidth(font, text, wrappingWidth); // Not supported by WebFX // Alternative WebFX code: if (Strings.isEmpty(text)) return 0; /*if (wrappingWidth <= 0) // Commented because it doesn't include the extra space around the text like in the html node return WebFxKitLauncher.measureText(text, font).getWidth();*/ - double textWidth = getTextToMeasure(font, text, wrappingWidth).prefWidth(-1); - if (wrappingWidth == 0) - noWrappingTextWidth = textWidth; - return textWidth; + return measureText(font, text, wrappingWidth, true); } private double computeTextHeight(Font font, String text, double wrappingWidth, double lineSpacing, TextBoundsType boundsType) { @@ -709,10 +706,11 @@ private double computeTextHeight(Font font, String text, double wrappingWidth, d // Alternative WebFX code: /*if (wrappingWidth <= 0 || Strings.isEmpty(text)) // Commented because it doesn't include the extra space around the text like in the html node return WebFxKitLauncher.measureText(text, font).getHeight();*/ - return getTextToMeasure(font, text, wrappingWidth).prefHeight(-1); + return measureText(font, text, wrappingWidth, false); // Note: this actually applies the wrappingWidth to the text + // TODO: check if there are cases where wrappingWidth = 0 is not applied to the text } - private Text getTextToMeasure(Font font, String text, double wrappingWidth) { // WebFX code + private double measureText(Font font, String text, double wrappingWidth, boolean width) { // WebFX code Text textToMesure; // Using noWrappingText (and not this.text) in case of computation with no wrappingWidth (which happens each // time JavaFX computes the label min and pref widths), because if we were using this.text, this constant @@ -732,7 +730,11 @@ private Text getTextToMeasure(Font font, String text, double wrappingWidth) { // textToMesure.setWrappingWidth(wrappingWidth); } FXProperties.setIfNotEquals(textToMesure.textProperty(), text); - return textToMesure; + // Measuring the text width or height. Note: prefHeight(-1) alone may cause wrong value at initialization (use Podcasts page to test) + double measure = width ? textToMesure.prefWidth(-1) : textToMesure.prefHeight(wrappingWidth > 0 ? wrappingWidth : -1); + if (width && wrappingWidth == 0) // Memorizing the width for the noWrappingText when it was measured + noWrappingTextWidth = measure; + return measure; } @Override protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { @@ -781,7 +783,7 @@ private double computeMinLabeledPartHeight(double width, double topInset, double double widthPadding = leftInset + leftLabelPadding() + rightInset + rightLabelPadding(); - double textWidth = emptyText ? 0 : computeTextWidth(font, string, 0); + double textWidth = emptyText ? 0 : computeTextWidth(font, string, 0); // Fix for RT-39889 double graphicWidth = graphic == null ? 0.0 : diff --git a/webfx-kit/webfx-kit-javafxgraphics-emul/src/main/java/javafx/scene/Node.java b/webfx-kit/webfx-kit-javafxgraphics-emul/src/main/java/javafx/scene/Node.java index 8c80672ff..19b49b5df 100644 --- a/webfx-kit/webfx-kit-javafxgraphics-emul/src/main/java/javafx/scene/Node.java +++ b/webfx-kit/webfx-kit-javafxgraphics-emul/src/main/java/javafx/scene/Node.java @@ -104,7 +104,7 @@ public void setScene(Scene scene) { this.scene.setValue(scene); } - private final Property managedProperty = new SimpleObjectProperty(true) { + private final BooleanProperty managedProperty = new SimpleBooleanProperty(true) { @Override protected void invalidated() { Parent parent = getParent(); @@ -115,13 +115,13 @@ protected void invalidated() { }; @Override - public Property managedProperty() { + public BooleanProperty managedProperty() { return managedProperty; } - private final Property mouseTransparentProperty = new SimpleObjectProperty<>(false); + private final BooleanProperty mouseTransparentProperty = new SimpleBooleanProperty(false); @Override - public Property mouseTransparentProperty() { + public BooleanProperty mouseTransparentProperty() { return mouseTransparentProperty; } @@ -163,9 +163,9 @@ public final EventHandler getOnContextMenuRequested() return getEventHandlerProperties().onMouseClickedProperty(); } - private final Property visibleProperty = new SimpleObjectProperty<>(true); + private final BooleanProperty visibleProperty = new SimpleBooleanProperty(true); @Override - public Property visibleProperty() { + public BooleanProperty visibleProperty() { return visibleProperty; } @@ -356,7 +356,7 @@ public final boolean isDisable() { * * @defaultValue false */ - private final Property disableProperty = new SimpleObjectProperty(false) { + private final BooleanProperty disableProperty = new SimpleBooleanProperty(false) { @Override protected void invalidated() { updateDisabled(); @@ -377,7 +377,7 @@ private void updateDisabled() { } }; - public final Property disableProperty() { + public final BooleanProperty disableProperty() { return disableProperty; //getMiscProperties().disableProperty(); } @@ -394,7 +394,7 @@ public final Property disableProperty() { * * @defaultValue false */ - private Property hover; + private BooleanProperty hover; protected final void setHover(boolean value) { hoverPropertyImpl().setValue(value); @@ -404,13 +404,13 @@ public final boolean isHover() { return hover == null ? false : hover.getValue(); } - public final ReadOnlyProperty hoverProperty() { + public final ReadOnlyBooleanProperty hoverProperty() { return hoverPropertyImpl()/*.getReadOnlyProperty()*/; } - private Property hoverPropertyImpl() { + private BooleanProperty hoverPropertyImpl() { if (hover == null) { - hover = new SimpleObjectProperty<>(false)/* { + hover = new SimpleBooleanProperty(false)/* { @Override protected void invalidated() { @@ -442,7 +442,7 @@ public String getName() { * * @defaultValue false */ - private Property pressed; + private BooleanProperty pressed; protected final void setPressed(boolean value) { pressedPropertyImpl().setValue(value); @@ -452,13 +452,13 @@ public final boolean isPressed() { return pressed == null ? false : pressed.getValue(); } - public final ReadOnlyProperty pressedProperty() { + public final ReadOnlyBooleanProperty pressedProperty() { return pressedPropertyImpl()/*.getReadOnlyProperty()*/; } - private Property pressedPropertyImpl() { + private BooleanProperty pressedPropertyImpl() { if (pressed == null) { - pressed = new SimpleObjectProperty<>(false)/* { + pressed = new SimpleBooleanProperty(false)/* { @Override protected void invalidated() { @@ -868,7 +868,7 @@ public final boolean impl_traverse(Direction dir) { * @see #requestFocus() * @defaultValue false */ - private Property focusTraversable; + private BooleanProperty focusTraversable; public final void setFocusTraversable(boolean value) { focusTraversableProperty().setValue(value); @@ -877,9 +877,9 @@ public final boolean isFocusTraversable() { return focusTraversable == null ? false : focusTraversable.getValue(); } - public final Property focusTraversableProperty() { + public final BooleanProperty focusTraversableProperty() { if (focusTraversable == null) { - focusTraversable = new SimpleObjectProperty<>(false)/* { + focusTraversable = new SimpleBooleanProperty(false)/* { @Override public void invalidated() { diff --git a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlNodePeer.java b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlNodePeer.java index fe4bbcecb..2c5b8130d 100644 --- a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlNodePeer.java +++ b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlNodePeer.java @@ -46,9 +46,9 @@ protected SvgRoot getSvgRoot() { @Override public void updateAllNodeTransforms(List allNodeTransforms) { Element container = getVisibleContainer(); - if (!(container instanceof HTMLElement)) + if (!(container instanceof HTMLElement)) // for SVG elements super.updateAllNodeTransforms(allNodeTransforms); - else { + else { // for HTML elements String transform = HtmlTransforms.toHtmlTransforms(allNodeTransforms); CSSStyleDeclaration style = ((HTMLElement) container).style; style.transform = transform; diff --git a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlSVGPathPeer.java b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlSVGPathPeer.java index 51e0a4569..44e5da7ac 100644 --- a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlSVGPathPeer.java +++ b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlSVGPathPeer.java @@ -71,8 +71,8 @@ public Bounds measureLayoutBounds() { } @Override - public double sizeAndMeasure(double value, boolean width) { - return width ? getBBox().width : getBBox().height; + public double sizeAndMeasure(boolean measureWidth, double otherSizeValue) { + return measureWidth ? getBBox().width : getBBox().height; } } diff --git a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlScenePeer.java b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlScenePeer.java index e4b48d917..16e61af1c 100644 --- a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlScenePeer.java +++ b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlScenePeer.java @@ -232,6 +232,7 @@ private void removeFromDocumentFonts(List fonts) { } private void onCssOrFontLoaded() { + // TODO: reset all caches in HtmlLayoutMeasurable forceWholeSceneGraphLayout(scene); } diff --git a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlSvgTextPeer.java b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlSvgTextPeer.java index 61604343b..67c49bee8 100644 --- a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlSvgTextPeer.java +++ b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlSvgTextPeer.java @@ -113,8 +113,8 @@ public void updateStrokeDashArray(List dashArray) { } @Override - public double measure(HTMLElement e, boolean width) { - return width ? getBBox().width : getBBox().height; + public double measure(HTMLElement e, boolean measureWidth) { + return measureWidth ? getBBox().width : getBBox().height; } /* diff --git a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlTextPeer.java b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlTextPeer.java index 17587b433..d4c1384ce 100644 --- a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlTextPeer.java +++ b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/HtmlTextPeer.java @@ -65,7 +65,7 @@ private String toCssTextShadow(DropShadow shadow) { @Override public void updateText(String text) { - setElementTextContent(text); + setElementTextContent(text); // this clears the cache (if text is different) updateYInAnimationFrame(true); } @@ -146,7 +146,7 @@ private void updateWrappingWithAndLineSpacing(double wrappingWidth, double lineS // First, we set the HTML line height with no extra spacing between lines (lineSpacing = 0). // Note: it looks like JavaFX doesn't apply the same line height for single-line and multi-lines texts. // For single-line, it looks like HTML "normal", and for multi-line it looks like 130% (empiric value). - style.lineHeight = isWrapping ? CSSProperties.LineHeightUnionType.of("130%") : null; // Note: 100% < normal < 130% + style.lineHeight = isWrapping ? CSSProperties.LineHeightUnionType.of("130%") : null /*or pre-wrap?*/; // Note: 100% < normal < 130% // We correct the line height if an additional line spacing is requested if (isWrapping && lineSpacing != 0) { // not necessary if not wrapping (i.e. single line text) // There is no HTML equivalent of the JavaFX lineSpacing which specifies only the extra space (expressed in @@ -162,8 +162,8 @@ private void updateWrappingWithAndLineSpacing(double wrappingWidth, double lineS // 2) Correcting the line height by adding the requested line spacing style.lineHeight = CSSProperties.LineHeightUnionType.of(toPx(lineHeightPx + lineSpacing)); } - // Mapping the wrapping with using the HTML width style attribute - style.width = isWrapping ? CSSProperties.WidthUnionType.of(toPx(wrappingWidth)) : null; + // Mapping the wrapping with using the HTML maxWidth style attribute + style.maxWidth = isWrapping ? CSSProperties.MaxWidthUnionType.of(toPx(wrappingWidth)) : null; // Mapping the wrapping mode using the HTML white-space style attribute style.whiteSpace = isWrapping ? "pre-wrap" : "pre"; // Clearing the measurement cache because HTML attributes have changed diff --git a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/layoutmeasurable/HtmlLayoutMeasurable.java b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/layoutmeasurable/HtmlLayoutMeasurable.java index 95dbe7302..e1e872cfd 100644 --- a/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/layoutmeasurable/HtmlLayoutMeasurable.java +++ b/webfx-kit/webfx-kit-javafxgraphics-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxgraphics/gwtj2cl/html/layoutmeasurable/HtmlLayoutMeasurable.java @@ -2,6 +2,7 @@ import dev.webfx.kit.mapper.peers.javafxgraphics.emul_coupling.LayoutMeasurable; import dev.webfx.kit.mapper.peers.javafxgraphics.gwtj2cl.html.HtmlNodePeer; +import dev.webfx.platform.console.Console; import elemental2.dom.CSSProperties; import elemental2.dom.CSSStyleDeclaration; import elemental2.dom.DOMRect; @@ -14,12 +15,16 @@ */ public interface HtmlLayoutMeasurable extends LayoutMeasurable { + // TODO: reset all caches when fonts are loaded from CSS + boolean ENABLE_CACHE = true; + boolean DETECT_WRONG_CACHE = false; + HTMLElement getElement(); default Bounds getLayoutBounds() { Bounds layoutBounds; // Looking the value in the cache (if the peer has one) - HtmlLayoutCache cache = getCache(); + HtmlLayoutCache cache = ENABLE_CACHE ? getCache() : null; if (cache != null) { layoutBounds = cache.getCachedLayoutBounds(); if (layoutBounds != null) @@ -64,49 +69,53 @@ default double prefHeight(double width) { } default double measureWidth(double height) { - return sizeAndMeasure(height, true); + return sizeAndMeasure(true, height); } default double measureHeight(double width) { - return sizeAndMeasure(width, false); + return sizeAndMeasure(false, width); } - default double sizeAndMeasure(double value, boolean width) { - HtmlLayoutCache cache = getCache(); - if (cache != null) { - double cachedSize = cache.getCachedSize(value, width); - if (cachedSize >= 0) - return cachedSize; - } + default double sizeAndMeasure(boolean measureWidth, double otherSizeValue) { + HtmlLayoutCache cache = ENABLE_CACHE ? getCache() : null; + double cachedSize = cache == null ? -1 : cache.getCachedSize(otherSizeValue, measureWidth); + if (!DETECT_WRONG_CACHE && cachedSize >= 0) + return cachedSize; HTMLElement e = getElement(); CSSStyleDeclaration style = e.style; CSSProperties.WidthUnionType styleWidth = style.width; CSSProperties.HeightUnionType styleHeight = style.height; - if (width) { + String pxValue = otherSizeValue >= 0 ? HtmlNodePeer.toPx(otherSizeValue) : null; + if (measureWidth) { style.width = null; - if (value >= 0) - style.height = CSSProperties.HeightUnionType.of(HtmlNodePeer.toPx(value)); + if (otherSizeValue >= 0) + style.height = CSSProperties.HeightUnionType.of(pxValue); } else { - if (value >= 0) - style.width = CSSProperties.WidthUnionType.of(HtmlNodePeer.toPx(value)); + if (otherSizeValue >= 0) + style.width = CSSProperties.WidthUnionType.of(pxValue); style.height = null; } - double result = measure(e, width); + double result = measure(e, measureWidth); + if (cache != null && e.isConnected) { // no cache for non-connected elements (as explained above) + if (DETECT_WRONG_CACHE && cachedSize >= 0 && cachedSize != result) { + Console.log("⚠️ Warning: cached " + (measureWidth ? "width" : "height") + " differs from measured: " + cachedSize + " != " + result + " for " + this + ", style = " + style.cssText); + } + cache.setCachedSize(otherSizeValue, measureWidth, result); + } + // Restoring the original style after measurement style.width = styleWidth; style.height = styleHeight; - if (cache != null && e.isConnected) // no cache for non-connected elements (as explained above) - cache.setCachedSize(value, width, result); return result; } - default double measure(HTMLElement e, boolean width) { + default double measure(HTMLElement e, boolean measureWidth) { // offsetWidth & offsetHeight return the correct values (including transforms), unfortunately their precision is // only integer... This diminution can cause problems (ex: text in Label wrapped to next line while it shouldn't). - int i = width ? e.offsetWidth : e.offsetHeight; + int i = measureWidth ? e.offsetWidth : e.offsetHeight; // So we try to get a better precision (double) using getBoundingClientRect(), unfortunately it doesn't consider // transforms... But we will prefer it in case there is no transforms DOMRect bcr = e.getBoundingClientRect(); - double d = width ? bcr.width : bcr.height; + double d = measureWidth ? bcr.width : bcr.height; if (i == (int) d) // If the double precision matches the integer precision, it's likely there is no transform, return d; // so we return this more precise value // Otherwise, it's likely that there is a transform, so we return the integer precision value diff --git a/webfx-kit/webfx-kit-javafxmedia-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxmedia/spi/gwtj2cl/GwtJ2clMediaViewPeer.java b/webfx-kit/webfx-kit-javafxmedia-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxmedia/spi/gwtj2cl/GwtJ2clMediaViewPeer.java index 034a6c41b..497b8d61d 100644 --- a/webfx-kit/webfx-kit-javafxmedia-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxmedia/spi/gwtj2cl/GwtJ2clMediaViewPeer.java +++ b/webfx-kit/webfx-kit-javafxmedia-peers-gwt-j2cl/src/main/java/dev/webfx/kit/mapper/peers/javafxmedia/spi/gwtj2cl/GwtJ2clMediaViewPeer.java @@ -102,7 +102,7 @@ private double getVideoHeight() { } @Override - public double measure(HTMLElement e, boolean width) { // Important correction of measure() for FireFox where offsetWidth/Height is not immediately equals to videoWidth/Height - return width ? getVideoWidth() : getVideoHeight(); + public double measure(HTMLElement e, boolean measureWidth) { // Important correction of measure() for FireFox where offsetWidth/Height is not immediately equals to videoWidth/Height + return measureWidth ? getVideoWidth() : getVideoHeight(); } }