mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JRE-210 JEditorPane may return wrong preferred size as it moves b/w monitors of different scale
(cherry picked from commit 6c3087e6bda32ae9b095e069d8bea614502f5c03)
(cherry picked from commit adb3a4be16)
This commit is contained in:
committed by
alexey.ushakov@jetbrains.com
parent
51212a481c
commit
b257f0f49e
@@ -25,6 +25,7 @@
|
||||
|
||||
package java.awt;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.applet.Applet;
|
||||
import java.awt.dnd.DropTarget;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -1194,7 +1195,15 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
if (graphicsConfig == gc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AffineTransform tx = graphicsConfig != null ? graphicsConfig.getDefaultTransform() : new AffineTransform();
|
||||
AffineTransform newTx = gc != null ? gc.getDefaultTransform() : new AffineTransform();
|
||||
graphicsConfig = gc;
|
||||
if (tx.getScaleX() != newTx.getScaleX() ||
|
||||
tx.getScaleY() != newTx.getScaleY())
|
||||
{
|
||||
firePropertyChange("graphicsContextScaleTransform", tx, newTx);
|
||||
}
|
||||
|
||||
ComponentPeer peer = this.peer;
|
||||
if (peer != null) {
|
||||
|
||||
@@ -1920,9 +1920,24 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory {
|
||||
updateCursor();
|
||||
modelChanged();
|
||||
}
|
||||
if (propertyName.equals("graphicsContextScaleTransform")) {
|
||||
// force re-layout of the document view
|
||||
forwardPreferenceChangeToView(rootView);
|
||||
}
|
||||
BasicTextUI.this.propertyChange(evt);
|
||||
}
|
||||
|
||||
private void forwardPreferenceChangeToView(View view) {
|
||||
if (view.getViewCount() == 0) {
|
||||
// propagate the change up the hierarchy of this leaf view
|
||||
view.preferenceChanged(null, true, true);
|
||||
return;
|
||||
}
|
||||
for (int i=0; i<view.getViewCount(); i++) {
|
||||
forwardPreferenceChangeToView(view.getView(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void dropIndexChanged() {
|
||||
if (editor.getDropMode() == DropMode.USE_SELECTION) {
|
||||
return;
|
||||
|
||||
@@ -292,6 +292,15 @@ public abstract class FlowView extends BoxView {
|
||||
strategy.changedUpdate(this, changes, getInsideAllocation(a));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void preferenceChanged(View child, boolean width, boolean height) {
|
||||
super.preferenceChanged(child, width, height);
|
||||
if (strategy instanceof TextLayoutStrategy) {
|
||||
((TextLayoutStrategy) strategy).syncFRC(this);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void setParent(View parent) {
|
||||
super.setParent(parent);
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
*/
|
||||
package javax.swing.text;
|
||||
|
||||
import sun.swing.SwingUtilities2;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
/**
|
||||
* A class to perform rendering of the glyphs.
|
||||
@@ -221,6 +224,15 @@ class GlyphPainter1 extends GlyphView.GlyphPainter {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
void sync(GlyphView v) {
|
||||
if (metrics != null) {
|
||||
AffineTransform frcTx = metrics.getFontRenderContext().getTransform();
|
||||
AffineTransform newFrcTx = SwingUtilities2.getFontRenderContext(v.getContainer()).getTransform();
|
||||
if (frcTx.getScaleX() != newFrcTx.getScaleX() ||
|
||||
frcTx.getScaleY() != newFrcTx.getScaleY())
|
||||
{
|
||||
metrics = null;
|
||||
}
|
||||
}
|
||||
Font f = v.getFont();
|
||||
FontMetrics fm = null;
|
||||
Container c = v.getContainer();
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.LineBreakMeasurer;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.BreakIterator;
|
||||
import java.util.HashSet;
|
||||
@@ -42,6 +43,7 @@ import javax.swing.JComponent;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
|
||||
import sun.font.BidiUtils;
|
||||
import sun.swing.SwingUtilities2;
|
||||
|
||||
/**
|
||||
* A flow strategy that uses java.awt.font.LineBreakMeasurer to
|
||||
@@ -289,6 +291,18 @@ class TextLayoutStrategy extends FlowView.FlowStrategy {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize the strategy if the container's FRC scale changes.
|
||||
*/
|
||||
void syncFRC(FlowView fv) {
|
||||
AffineTransform newFrcTx = SwingUtilities2.getFontRenderContext(fv.getContainer()).getTransform();
|
||||
if (frcTx.getScaleX() != newFrcTx.getScaleX() ||
|
||||
frcTx.getScaleY() != newFrcTx.getScaleY())
|
||||
{
|
||||
sync(fv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize the strategy with its FlowView. Allows the strategy
|
||||
* to update its state to account for changes in that portion of the
|
||||
@@ -302,6 +316,8 @@ class TextLayoutStrategy extends FlowView.FlowStrategy {
|
||||
Container container = fv.getContainer();
|
||||
FontRenderContext frc = sun.swing.SwingUtilities2.
|
||||
getFontRenderContext(container);
|
||||
frcTx = frc.getTransform();
|
||||
|
||||
BreakIterator iter;
|
||||
Container c = fv.getContainer();
|
||||
if (c != null) {
|
||||
@@ -344,6 +360,7 @@ class TextLayoutStrategy extends FlowView.FlowStrategy {
|
||||
|
||||
private LineBreakMeasurer measurer;
|
||||
private AttributedSegment text;
|
||||
private AffineTransform frcTx = new AffineTransform();
|
||||
|
||||
/**
|
||||
* Implementation of AttributedCharacterIterator that supports
|
||||
|
||||
@@ -1251,6 +1251,13 @@ public class SwingUtilities2 {
|
||||
|
||||
GraphicsConfiguration gc = c.getGraphicsConfiguration();
|
||||
AffineTransform tx = (gc == null) ? null : gc.getDefaultTransform();
|
||||
if (tx == null && !GraphicsEnvironment.isHeadless()) {
|
||||
tx = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice()
|
||||
.getDefaultConfiguration()
|
||||
.getDefaultTransform();
|
||||
}
|
||||
Object aaHint = c.getClientProperty(KEY_TEXT_ANTIALIASING);
|
||||
return getFRCFromCache(tx, aaHint);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
body { font-family: Segoe UI; font-size: 12pt; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* bug JRE-210
|
||||
* @summary JEditorPane's font metrics to honour switching to different GC scale
|
||||
* @author anton.tarasov
|
||||
* @requires (os.family == "windows")
|
||||
* @run main JEditorPaneGCSwitchTest
|
||||
*/
|
||||
public class JEditorPaneGCSwitchTest {
|
||||
static JEditorPane editorPane;
|
||||
static JFrame frame;
|
||||
volatile static CountDownLatch latch;
|
||||
final static Map<Float, Dimension> scale2size = new HashMap<>(2);
|
||||
|
||||
static void initGUI() {
|
||||
editorPane = new JEditorPane() {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
}
|
||||
};
|
||||
try {
|
||||
// This HTML text has different bounds when put into GC's with different scales
|
||||
editorPane.setPage(JEditorPaneGCSwitchTest.class.getResource("JEditorPaneGCSwitchTest.html"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
editorPane.addPropertyChangeListener("page", (e) -> {
|
||||
if (frame != null) frame.dispose();
|
||||
frame = new JFrame("frame");
|
||||
frame.add(editorPane);
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
latch.countDown();
|
||||
});
|
||||
}
|
||||
|
||||
static void testSize(final float scale) {
|
||||
// Emulate showing on a device with the provided scale
|
||||
AWTAccessor.getComponentAccessor().setGraphicsConfiguration(editorPane, new MyGraphicsConfiguration(scale));
|
||||
|
||||
EventQueue.invokeLater(() -> {
|
||||
Dimension d = editorPane.getPreferredSize();
|
||||
System.out.println(scale + " : " + d);
|
||||
scale2size.put(scale, d);
|
||||
latch.countDown();
|
||||
});
|
||||
}
|
||||
|
||||
static void runSync(Runnable r) {
|
||||
try {
|
||||
latch = new CountDownLatch(1);
|
||||
SwingUtilities.invokeLater(() -> r.run());
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
/*
|
||||
* 1. Recreate the editor b/w device switch
|
||||
*/
|
||||
runSync(() -> initGUI());
|
||||
|
||||
runSync(() -> testSize(1f));
|
||||
|
||||
runSync(() -> initGUI());
|
||||
|
||||
runSync(() -> testSize(2f));
|
||||
|
||||
if (scale2size.get(1f).equals(scale2size.get(2f))) {
|
||||
throw new RuntimeException("Test FAILED: [1] expected different editor size per scale!");
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. Keep the editor shown b/w device switch
|
||||
*/
|
||||
scale2size.clear();
|
||||
|
||||
runSync(() -> initGUI());
|
||||
|
||||
runSync(() -> testSize(1f));
|
||||
|
||||
runSync(() -> testSize(2f));
|
||||
|
||||
frame.dispose();
|
||||
|
||||
if (scale2size.get(1f).equals(scale2size.get(2f))) {
|
||||
throw new RuntimeException("Test FAILED: [2] expected different editor size per scale!");
|
||||
}
|
||||
System.out.println("Test PASSED");
|
||||
}
|
||||
|
||||
static class MyGraphicsConfiguration extends GraphicsConfiguration {
|
||||
GraphicsConfiguration delegate;
|
||||
float scale;
|
||||
|
||||
public MyGraphicsConfiguration(float scale) {
|
||||
this.delegate = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsDevice getDevice() {
|
||||
return delegate.getDevice();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorModel getColorModel() {
|
||||
return delegate.getColorModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorModel getColorModel(int transparency) {
|
||||
return delegate.getColorModel(transparency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AffineTransform getDefaultTransform() {
|
||||
return AffineTransform.getScaleInstance(scale, scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AffineTransform getNormalizingTransform() {
|
||||
return delegate.getNormalizingTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
return delegate.getBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* bug JRE-210
|
||||
* @summary JEditorPane's font metrics to honour switching to different GC scale
|
||||
* @author anton.tarasov
|
||||
* @requires (os.family == "windows")
|
||||
* @run main/othervm -Dsun.font.layoutengine=icu -Di18n=true JEditorPaneGCSwitchTest_i18n
|
||||
*/
|
||||
// -Dsun.font.layoutengine=icu is used while Harfbuzz crashes with i18n
|
||||
public class JEditorPaneGCSwitchTest_i18n extends JPanel {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
JEditorPaneGCSwitchTest.main(null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user