Skip to content

Commit

Permalink
8130738: Add tabSize property to Text and TextFlow
Browse files Browse the repository at this point in the history
Reviewed-by: prr, kcr
  • Loading branch information
Scott Palmer authored and kevinrushforth committed Dec 31, 2019
1 parent 69e4ef3 commit 8367e1a
Show file tree
Hide file tree
Showing 9 changed files with 466 additions and 68 deletions.
Expand Up @@ -3028,6 +3028,12 @@ <h4><a id="text">Text</a></h4>
<td>&nbsp;</td> <td>&nbsp;</td>
</tr> </tr>
<tr> <tr>
<th class="propertyname" scope="row">-fx-tab-size</th>
<td class="value"><a href="#typenumber" class="typelink">&lt;integer&gt;</a></td>
<td>8</td>
<td>&nbsp;</td>
</tr>
<tr>
<th class="propertyname" scope="row">-fx-text-alignment</th> <th class="propertyname" scope="row">-fx-text-alignment</th>
<td class="value">[ left | center | right | justify ] </td> <td class="value">[ left | center | right | justify ] </td>
<td>left</td> <td>left</td>
Expand Down
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -75,6 +75,8 @@ public interface TextLayout {
public static final int TYPE_TOP = 1 << 4; public static final int TYPE_TOP = 1 << 4;
public static final int TYPE_BEARINGS = 1 << 5; public static final int TYPE_BEARINGS = 1 << 5;


public static final int DEFAULT_TAB_SIZE = 8;

public static class Hit { public static class Hit {
int charIndex; int charIndex;
int insertionIndex; int insertionIndex;
Expand Down Expand Up @@ -188,6 +190,15 @@ public Hit(int charIndex, int insertionIndex, boolean leading) {
*/ */
public Shape getShape(int type, TextSpan filter); public Shape getShape(int type, TextSpan filter);


/**
* Sets the tab size for the TextLayout.
*
* @param spaces the number of spaces represented by a tab. Default is 8.
* Minimum is 1, lower values will be clamped to 1.
* @return returns true if the call modifies the layout internal state.
*/
public boolean setTabSize(int spaces);

public Hit getHitInfo(float x, float y); public Hit getHitInfo(float x, float y);


public PathElement[] getCaretShape(int offset, boolean isLeading, public PathElement[] getCaretShape(int offset, boolean isLeading,
Expand Down
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -80,6 +80,7 @@ public class PrismTextLayout implements TextLayout {
private LayoutCache layoutCache; private LayoutCache layoutCache;
private Shape shape; private Shape shape;
private int flags; private int flags;
private int tabSize = DEFAULT_TAB_SIZE;


public PrismTextLayout() { public PrismTextLayout() {
logicalBounds = new RectBounds(); logicalBounds = new RectBounds();
Expand Down Expand Up @@ -648,6 +649,19 @@ public Shape getShape(int type, TextSpan filter) {
return outline; return outline;
} }


@Override
public boolean setTabSize(int spaces) {
if (spaces < 1) {
spaces = 1;
}
if (tabSize != spaces) {
tabSize = spaces;
relayout();
return true;
}
return false;
}

/*************************************************************************** /***************************************************************************
* * * *
* Text Layout Implementation * * Text Layout Implementation *
Expand Down Expand Up @@ -1004,7 +1018,7 @@ private float getTabAdvance() {
} else { } else {
spaceAdvance = strike.getCharAdvance(' '); spaceAdvance = strike.getCharAdvance(' ');
} }
return 8 * spaceAdvance; return tabSize * spaceAdvance;
} }


private void layout() { private void layout() {
Expand Down
164 changes: 122 additions & 42 deletions modules/javafx.graphics/src/main/java/javafx/scene/text/Text.java
Expand Up @@ -82,6 +82,7 @@
import javafx.css.Styleable; import javafx.css.Styleable;
import javafx.css.StyleableBooleanProperty; import javafx.css.StyleableBooleanProperty;
import javafx.css.StyleableDoubleProperty; import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableIntegerProperty;
import javafx.css.StyleableObjectProperty; import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty; import javafx.css.StyleableProperty;
import javafx.geometry.BoundingBox; import javafx.geometry.BoundingBox;
Expand Down Expand Up @@ -307,6 +308,7 @@ private TextLayout getTextLayout() {
} else { } else {
layout.setDirection(TextLayout.DIRECTION_LTR); layout.setDirection(TextLayout.DIRECTION_LTR);
} }
layout.setTabSize(getTabSize());
} }
return layout; return layout;
} }
Expand Down Expand Up @@ -1267,6 +1269,30 @@ private com.sun.javafx.geom.Shape doConfigShape() {
return TransformedShape.translatedShape(shape, x, y); return TransformedShape.translatedShape(shape, x, y);
} }


/**
* The size of a tab stop in spaces.
* Values less than 1 are treated as 1.
*
* @defaultValue 8
*
* @since 14
*/
public final IntegerProperty tabSizeProperty() {
return getTextAttribute().tabSizeProperty();
}

public final int getTabSize() {
if (attributes == null || attributes.tabSize == null) {
return TextLayout.DEFAULT_TAB_SIZE;
}
return getTextAttribute().getTabSize();
}

public final void setTabSize(int spaces) {
tabSizeProperty().set(spaces);
}


/*************************************************************************** /***************************************************************************
* * * *
* Stylesheet Handling * * Stylesheet Handling *
Expand All @@ -1276,9 +1302,9 @@ private com.sun.javafx.geom.Shape doConfigShape() {
/* /*
* Super-lazy instantiation pattern from Bill Pugh. * Super-lazy instantiation pattern from Bill Pugh.
*/ */
private static class StyleableProperties { private static class StyleableProperties {


private static final CssMetaData<Text,Font> FONT = private static final CssMetaData<Text,Font> FONT =
new FontCssMetaData<Text>("-fx-font", Font.getDefault()) { new FontCssMetaData<Text>("-fx-font", Font.getDefault()) {


@Override @Override
Expand All @@ -1290,11 +1316,11 @@ public boolean isSettable(Text node) {
public StyleableProperty<Font> getStyleableProperty(Text node) { public StyleableProperty<Font> getStyleableProperty(Text node) {
return (StyleableProperty<Font>)node.fontProperty(); return (StyleableProperty<Font>)node.fontProperty();
} }
}; };


private static final CssMetaData<Text,Boolean> UNDERLINE = private static final CssMetaData<Text,Boolean> UNDERLINE =
new CssMetaData<Text,Boolean>("-fx-underline", new CssMetaData<Text,Boolean>("-fx-underline",
BooleanConverter.getInstance(), Boolean.FALSE) { BooleanConverter.getInstance(), Boolean.FALSE) {


@Override @Override
public boolean isSettable(Text node) { public boolean isSettable(Text node) {
Expand All @@ -1307,11 +1333,11 @@ public boolean isSettable(Text node) {
public StyleableProperty<Boolean> getStyleableProperty(Text node) { public StyleableProperty<Boolean> getStyleableProperty(Text node) {
return (StyleableProperty<Boolean>)node.underlineProperty(); return (StyleableProperty<Boolean>)node.underlineProperty();
} }
}; };


private static final CssMetaData<Text,Boolean> STRIKETHROUGH = private static final CssMetaData<Text,Boolean> STRIKETHROUGH =
new CssMetaData<Text,Boolean>("-fx-strikethrough", new CssMetaData<Text,Boolean>("-fx-strikethrough",
BooleanConverter.getInstance(), Boolean.FALSE) { BooleanConverter.getInstance(), Boolean.FALSE) {


@Override @Override
public boolean isSettable(Text node) { public boolean isSettable(Text node) {
Expand All @@ -1324,13 +1350,13 @@ public boolean isSettable(Text node) {
public StyleableProperty<Boolean> getStyleableProperty(Text node) { public StyleableProperty<Boolean> getStyleableProperty(Text node) {
return (StyleableProperty<Boolean>)node.strikethroughProperty(); return (StyleableProperty<Boolean>)node.strikethroughProperty();
} }
}; };


private static final private static final
CssMetaData<Text,TextAlignment> TEXT_ALIGNMENT = CssMetaData<Text,TextAlignment> TEXT_ALIGNMENT =
new CssMetaData<Text,TextAlignment>("-fx-text-alignment", new CssMetaData<Text,TextAlignment>("-fx-text-alignment",
new EnumConverter<TextAlignment>(TextAlignment.class), new EnumConverter<TextAlignment>(TextAlignment.class),
TextAlignment.LEFT) { TextAlignment.LEFT) {


@Override @Override
public boolean isSettable(Text node) { public boolean isSettable(Text node) {
Expand All @@ -1343,12 +1369,12 @@ public boolean isSettable(Text node) {
public StyleableProperty<TextAlignment> getStyleableProperty(Text node) { public StyleableProperty<TextAlignment> getStyleableProperty(Text node) {
return (StyleableProperty<TextAlignment>)node.textAlignmentProperty(); return (StyleableProperty<TextAlignment>)node.textAlignmentProperty();
} }
}; };


private static final CssMetaData<Text,VPos> TEXT_ORIGIN = private static final CssMetaData<Text,VPos> TEXT_ORIGIN =
new CssMetaData<Text,VPos>("-fx-text-origin", new CssMetaData<Text,VPos>("-fx-text-origin",
new EnumConverter<VPos>(VPos.class), new EnumConverter<VPos>(VPos.class),
VPos.BASELINE) { VPos.BASELINE) {


@Override @Override
public boolean isSettable(Text node) { public boolean isSettable(Text node) {
Expand All @@ -1361,14 +1387,14 @@ public boolean isSettable(Text node) {
public StyleableProperty<VPos> getStyleableProperty(Text node) { public StyleableProperty<VPos> getStyleableProperty(Text node) {
return (StyleableProperty<VPos>)node.textOriginProperty(); return (StyleableProperty<VPos>)node.textOriginProperty();
} }
}; };


private static final CssMetaData<Text,FontSmoothingType> private static final CssMetaData<Text,FontSmoothingType>
FONT_SMOOTHING_TYPE = FONT_SMOOTHING_TYPE =
new CssMetaData<Text,FontSmoothingType>( new CssMetaData<Text,FontSmoothingType>(
"-fx-font-smoothing-type", "-fx-font-smoothing-type",
new EnumConverter<FontSmoothingType>(FontSmoothingType.class), new EnumConverter<FontSmoothingType>(FontSmoothingType.class),
FontSmoothingType.GRAY) { FontSmoothingType.GRAY) {


@Override @Override
public boolean isSettable(Text node) { public boolean isSettable(Text node) {
Expand All @@ -1382,12 +1408,12 @@ public boolean isSettable(Text node) {


return (StyleableProperty<FontSmoothingType>)node.fontSmoothingTypeProperty(); return (StyleableProperty<FontSmoothingType>)node.fontSmoothingTypeProperty();
} }
}; };


private static final private static final
CssMetaData<Text,Number> LINE_SPACING = CssMetaData<Text,Number> LINE_SPACING =
new CssMetaData<Text,Number>("-fx-line-spacing", new CssMetaData<Text,Number>("-fx-line-spacing",
SizeConverter.getInstance(), 0) { SizeConverter.getInstance(), 0) {


@Override @Override
public boolean isSettable(Text node) { public boolean isSettable(Text node) {
Expand All @@ -1400,14 +1426,14 @@ public boolean isSettable(Text node) {
public StyleableProperty<Number> getStyleableProperty(Text node) { public StyleableProperty<Number> getStyleableProperty(Text node) {
return (StyleableProperty<Number>)node.lineSpacingProperty(); return (StyleableProperty<Number>)node.lineSpacingProperty();
} }
}; };


private static final CssMetaData<Text, TextBoundsType> private static final CssMetaData<Text, TextBoundsType>
BOUNDS_TYPE = BOUNDS_TYPE =
new CssMetaData<Text,TextBoundsType>( new CssMetaData<Text,TextBoundsType>(
"-fx-bounds-type", "-fx-bounds-type",
new EnumConverter<TextBoundsType>(TextBoundsType.class), new EnumConverter<TextBoundsType>(TextBoundsType.class),
DEFAULT_BOUNDS_TYPE) { DEFAULT_BOUNDS_TYPE) {


@Override @Override
public boolean isSettable(Text node) { public boolean isSettable(Text node) {
Expand All @@ -1418,10 +1444,27 @@ public boolean isSettable(Text node) {
public StyleableProperty<TextBoundsType> getStyleableProperty(Text node) { public StyleableProperty<TextBoundsType> getStyleableProperty(Text node) {
return (StyleableProperty<TextBoundsType>)node.boundsTypeProperty(); return (StyleableProperty<TextBoundsType>)node.boundsTypeProperty();
} }
}; };

private static final CssMetaData<Text, Number> TAB_SIZE =
new CssMetaData<Text,Number>("-fx-tab-size",
SizeConverter.getInstance(), TextLayout.DEFAULT_TAB_SIZE) {

@Override
public boolean isSettable(Text node) {
return node.attributes == null ||
node.attributes.tabSize == null ||
!node.attributes.tabSize.isBound();
}

@Override
public StyleableProperty<Number> getStyleableProperty(Text node) {
return (StyleableProperty<Number>)node.tabSizeProperty();
}
};


private final static List<CssMetaData<? extends Styleable, ?>> STYLEABLES; private final static List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
static { static {
final List<CssMetaData<? extends Styleable, ?>> styleables = final List<CssMetaData<? extends Styleable, ?>> styleables =
new ArrayList<CssMetaData<? extends Styleable, ?>>(Shape.getClassCssMetaData()); new ArrayList<CssMetaData<? extends Styleable, ?>>(Shape.getClassCssMetaData());
styleables.add(FONT); styleables.add(FONT);
Expand All @@ -1432,8 +1475,9 @@ public StyleableProperty<TextBoundsType> getStyleableProperty(Text node) {
styleables.add(FONT_SMOOTHING_TYPE); styleables.add(FONT_SMOOTHING_TYPE);
styleables.add(LINE_SPACING); styleables.add(LINE_SPACING);
styleables.add(BOUNDS_TYPE); styleables.add(BOUNDS_TYPE);
styleables.add(TAB_SIZE);
STYLEABLES = Collections.unmodifiableList(styleables); STYLEABLES = Collections.unmodifiableList(styleables);
} }
} }


/** /**
Expand Down Expand Up @@ -1821,6 +1865,37 @@ final BooleanProperty caretBiasProperty() {
} }
return caretBias; return caretBias;
} }

private IntegerProperty tabSize;

final int getTabSize() {
return tabSize == null ? TextLayout.DEFAULT_TAB_SIZE : tabSize.get();
}

final IntegerProperty tabSizeProperty() {
if (tabSize == null) {
tabSize = new StyleableIntegerProperty(TextLayout.DEFAULT_TAB_SIZE) {
@Override public Object getBean() { return Text.this; }
@Override public String getName() { return "tabSize"; }
@Override public CssMetaData getCssMetaData() {
return StyleableProperties.TAB_SIZE;
}
@Override protected void invalidated() {
if (!isSpan()) {
TextLayout layout = getTextLayout();
if (layout.setTabSize(get())) {
needsTextLayout();
}
NodeHelper.markDirty(Text.this, DirtyBits.TEXT_ATTRS);
if (getBoundsType() == TextBoundsType.VISUAL) {
NodeHelper.geomChanged(Text.this);
}
}
}
};
}
return tabSize;
}
} }


/** /**
Expand Down Expand Up @@ -1853,6 +1928,11 @@ public String toString() {
sb.append(", wrappingWidth=").append(wrap); sb.append(", wrappingWidth=").append(wrap);
} }


int tab = getTabSize();
if (tab != TextLayout.DEFAULT_TAB_SIZE) {
sb.append(", tabSize=").append(tab);
}

sb.append(", font=").append(getFont()); sb.append(", font=").append(getFont());
sb.append(", fontSmoothingType=").append(getFontSmoothingType()); sb.append(", fontSmoothingType=").append(getFontSmoothingType());


Expand Down

0 comments on commit 8367e1a

Please sign in to comment.