Bug 218087 - caret size and location incorrect on Mac Retina display
caret size and location incorrect on Mac Retina display
Status: RESOLVED INCOMPLETE
Product: platform
Classification: Unclassified
Component: JDK Problems
7.2
Macintosh (x86) Mac OS X
: P3 with 1 vote (vote)
: TBD
Assigned To: Stanislav Aubrecht
issues@platform
:
Depends on:
Blocks: 179047
  Show dependency treegraph
 
Reported: 2012-09-11 01:16 UTC by err
Modified: 2013-07-31 14:37 UTC (History)
5 users (show)

See Also:
Issue Type: DEFECT
:


Attachments
module to gather debug info from jVi (312.07 KB, application/octet-stream)
2012-11-22 03:20 UTC, err
Details

Note You need to log in before you can comment on or make changes to this bug.
Description err 2012-09-11 01:16:18 UTC
Might be jVi only, reported at SourceForge "Caret not visible on retina display" https://sourceforge.net/tracker/?func=detail&atid=103653&aid=3565919&group_id=3653

jVi has "class NbCaret extends ExtCaret" and it overrides
    NbCaret::paintCustomCaret(Graphics g).
It draws it's block caret something like
    Rectangle r = component.getUI().modelToView(component, dot);
    ... // modelToView used for x,y. calculate width/height as needed
    g.fillRect(r.x, r.y, r.width, r.height)
This doesn't work with the Retina display. Both the location and calculations are wrong. (BTW, I've seen bug#215141, but not sure what it all means)

I'm updating my main-silver clone to take a look at NbCaret, but I'm filing this for reference and suggestions...
Comment 1 err 2012-09-11 15:35:44 UTC
Looking through NB's BaseCaret code, I don't see anything special for scaling or dealing with high resolution displays. I wonder if there is a reasonable expectation that the problem goes away with 7.2.1 patch release.

Unfortunately, I don't have one of these devices to try daily builds.

It may be that jVi's code is violating some contract or assumption, but...
Comment 2 runand 2012-10-05 08:04:22 UTC
I have tested on os x in a recently dev-build: 201210040002 and version 7.3 beta, they both have the same problem.
Comment 3 err 2012-10-08 16:20:00 UTC
Mila,

Neither 7.3 beta nor daily build fixes jVi caret size/location problem on Mac Retina; works without jVi. I don't have access to a Retina, so I'm relying on a user report.

I don't see anything suspicious in NB's BaseCaret. Any ideas on what might be going on?
Comment 4 Miloslav Metelka 2012-10-09 08:49:08 UTC
Unfortunately I don't have access to any Mac with retina display so the only thing that I can recommend now is to use a new build with a fix from
bug#215141 (fixes NB to not look blurry on retina display) whether it would have any effect on the caret as well.

Also the loggers

-J-Dorg.netbeans.modules.editor.lib2.view.FontInfo.level=FINE
-J-Dorg.netbeans.editor.BaseCaret.level=FINE 

would show font sizes being used by view hierarchy and
the line containing "updateCaretBounds" there should be caret bounds computed so if they would have any suspicious values we might investigate then.
Comment 5 shanepbrady 2012-11-21 22:23:34 UTC
Hope this helps:
FINE [org.netbeans.editor.BaseCaret]: Installing to
org.openide.text.QuietEditorPane@381702ff
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=null
FINE [org.netbeans.editor.BaseCaret]: Deinstalling from
org.openide.text.QuietEditorPane@381702ff
FINE [org.netbeans.editor.BaseCaret]: Installing to
org.openide.text.QuietEditorPane@381702ff
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=null
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=null
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=359
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=null
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: old=null,
new=java.awt.Rectangle[x=48,y=168,width=10,height=14], offset=359
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=48,y=168,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=48,y=168,width=10,height=14],
new=java.awt.Rectangle[x=48,y=168,width=10,height=14], offset=359
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=48,y=168,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=48,y=168,width=10,height=14],
new=java.awt.Rectangle[x=48,y=168,width=10,height=14], offset=359
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=48,y=168,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=48,y=168,width=10,height=14],
new=java.awt.Rectangle[x=48,y=168,width=10,height=14], offset=359
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=48,y=168,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=48,y=168,width=10,height=14],
new=java.awt.Rectangle[x=48,y=168,width=10,height=14], offset=359
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=48,y=168,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=271
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=48,y=168,width=10,height=14],
new=java.awt.Rectangle[x=120,y=98,width=8,height=14], offset=271
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=120,y=98,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: moveDot: offset=271
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=120,y=98,width=8,height=14],
new=java.awt.Rectangle[x=120,y=98,width=8,height=14], offset=271
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=120,y=98,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=120,y=98,width=8,height=14],
new=java.awt.Rectangle[x=120,y=98,width=8,height=14], offset=271
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=120,y=98,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=120,y=98,width=8,height=14],
new=java.awt.Rectangle[x=120,y=98,width=8,height=14], offset=271
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=120,y=98,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=120,y=98,width=8,height=14],
new=java.awt.Rectangle[x=120,y=98,width=8,height=14], offset=271
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=120,y=98,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=120,y=98,width=8,height=14],
new=java.awt.Rectangle[x=120,y=98,width=8,height=14], offset=271
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=120,y=98,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=298
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=120,y=98,width=8,height=14],
new=java.awt.Rectangle[x=80,y=112,width=10,height=14], offset=298
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=80,y=112,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=80,y=112,width=10,height=14],
new=java.awt.Rectangle[x=80,y=112,width=10,height=14], offset=298
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=80,y=112,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=80,y=112,width=10,height=14],
new=java.awt.Rectangle[x=80,y=112,width=10,height=14], offset=298
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=80,y=112,width=10,height=14]
-Dorg.netbeans.modules.editor.lib2.view.FontInfo.level=FINE
-Dorg.netbeans.editor.BaseCaret.level=FINE
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=309
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=80,y=112,width=10,height=14],
new=java.awt.Rectangle[x=72,y=126,width=10,height=14], offset=309
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=72,y=126,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=72,y=126,width=10,height=14],
new=java.awt.Rectangle[x=72,y=126,width=10,height=14], offset=309
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=72,y=126,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=326
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=72,y=126,width=10,height=14],
new=java.awt.Rectangle[x=120,y=140,width=8,height=14], offset=326
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=120,y=140,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=120,y=140,width=8,height=14],
new=java.awt.Rectangle[x=120,y=140,width=8,height=14], offset=326
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=120,y=140,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=309
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=120,y=140,width=8,height=14],
new=java.awt.Rectangle[x=72,y=126,width=10,height=14], offset=309
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=72,y=126,width=10,height=14]
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds:
old=java.awt.Rectangle[x=72,y=126,width=10,height=14],
new=java.awt.Rectangle[x=72,y=126,width=10,height=14], offset=309
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change,
old=java.awt.Rectangle[x=72,y=126,width=10,height=14]
Comment 6 shanepbrady 2012-11-21 22:24:22 UTC
Every version of NB from 7.0.1 to the latest daily build has a missing caret in JVI with a Retina Mac
Comment 7 err 2012-11-22 03:20:20 UTC
Created attachment 128237 [details]
module to gather debug info from jVi

Install attached module and turn on new flag
-J-Dcom.raelity.jvi.swing.SwingPaintCaret.level=FINEST
In addition to flags indicated in comment 4

The output rectangle is from this sequence
                g.setColor(component.getCaretColor());
                g.setXORMode(component.getBackground());
                    g.fillRect(r.x, r.y, r.width, r.height);
Comment 8 err 2012-11-22 03:25:15 UTC
Adding shanepbrady to cc list. He might provide additional debug info.
Comment 9 Miloslav Metelka 2012-11-22 10:30:45 UTC
Thanks for the output. The caret size on Retina display looks similar to the one a regular display e.g. I have (on Ubuntu 12.04; Monospaced 12)

FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: old=java.awt.Rectangle[x=21,y=15,width=7,height=15], new=java.awt.Rectangle[x=21,y=30,width=7,height=15], offset=36

so I guess there's something between the display and the java app attempts to emulate a "regular" resolution for the java app (I guess that this relates to whether NSHighResolutionCapable is used or not in Info.plist or is the output the same in both cases??).
 Still I don't know what's wrong. I guess that you've already checked issue http://netbeans.org/bugzilla/show_bug.cgi?id=215141 (there's now a JDK issue filed for the NB on Retina display).
Comment 10 shanepbrady 2012-11-22 15:43:57 UTC
I have looked at that bug, but I'm currently on JDK 1.6 still, so I haven't had to worry about that yet.
Comment 11 err 2012-11-22 16:03:16 UTC
(In reply to comment #9)

> so I guess there's something between the display and the java app attempts to
> emulate a "regular" resolution for the java app

But why does jVi cursor disappear and the regular NB one work (except for the blurry thing)?

I wonder if jVi is doing something that turns off this emulation? jVi does install its own cursor.
Comment 12 err 2012-11-22 18:29:30 UTC
Shane,
Can you provide some additional output with the new module, as described in comment #7 ? That would verify that jVi is using the same bounds as NB (that is expected but just in case...)
Comment 13 shanepbrady 2012-11-26 15:56:47 UTC
Will be checking it out right now
Comment 14 shanepbrady 2012-11-27 02:15:45 UTC
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=463
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: old=java.awt.Rectangle[x=104,y=280,width=8,height=14], new=java.awt.Rectangle[x=104,y=294,width=8,height=14], offset=463
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change, old=java.awt.Rectangle[x=104,y=294,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=493
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: old=java.awt.Rectangle[x=104,y=294,width=8,height=14], new=java.awt.Rectangle[x=104,y=308,width=8,height=14], offset=493
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change, old=java.awt.Rectangle[x=104,y=308,width=8,height=14]
FINE [org.netbeans.editor.BaseCaret]: setDot: offset=520
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: old=java.awt.Rectangle[x=104,y=308,width=8,height=14], new=java.awt.Rectangle[x=104,y=322,width=8,height=14], offset=520
FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change, old=java.awt.Rectangle[x=104,y=322,width=8,height=14]
Comment 15 err 2012-11-27 02:22:54 UTC
I don't see any jVi output. Did you install the new module and set the debug flag?
Comment 16 err 2012-11-27 21:34:30 UTC
After some testing by shanepbrady, it looks like jVi is getting the same bounds as NB. In one test, jVi is dynamically disabled and NB cursor appears. jVi is using g.fillRect(...) as shown in comment #7.

Any further thoughts on how to track this down?


FINE [org.netbeans.editor.BaseCaret]: updateCaretBounds: no change, old=java.awt.Rectangle[x=128,y=224,width=8,height=14]
FINEST [com.raelity.jvi.swing.SwingPaintCaret]: jViCaret: java.awt.Rectangle[x=128,y=224,width=8,height=14]
Comment 17 err 2012-12-15 17:38:38 UTC
After some experiments by shanepbrady there is a workaround for jVi.

The code which jVi uses to paint the caret is essentially

        g.setColor(component.getCaretColor());
        g.setXORMode(component.getBackground());
        g.fillRect(r.x, r.y, r.width, r.height);

If the "g.setXORMode(...)" is commented out, then the cursor is visible.

Two issues,
- How can jVi detect that it is running on a system that has this problem
  (I'd rather not have a -Dxxx to turn it on)
- Whose bug is it and exactly what is the bug? (didn't see anything searching)
Comment 18 err 2013-01-11 18:17:53 UTC
Mila,

Now that this issue has been associated with the use of "g.setXORMode(...)", it doesn't seem to be an editor issue, does it?

Any idea on to where it should be assigned?
Comment 19 charlestang 2013-01-12 09:06:16 UTC
Hi, I change the code a little, everything looks OK.
I don't know why, but it works. Hope this can help you guys to fix this problem.
Thank you!


                g.setColor(component.getCaretColor());
		//g.setXORMode(component.getBackground());     <-------comment this line
                if(drawNormal) {
                    g.fillRect(r.x, r.y, r.width, r.height);
                    // drawing the char over the cursor derived from NB
                     //<----------- uncomment the following lines  [START]---
                    if(cursorShape == ViCaretStyle.SHAPE_BLOCK
                             && dotChar != null
                             && !Character.isWhitespace(dotChar[0])
                     ) {
                         Color textBackgroundColor = component.getBackground();
                         if (textBackgroundColor != null)
                             g.setColor(textBackgroundColor);
                         // int ascent = FontMetricsCache.getFontMetrics(afterCaretFont, c).getAscent();
                         g.drawChars(dotChar, 0, 1, r.x,
                                 r.y + fm.getAscent());
                                 // r.y + editorUI.getLineAscent());
                     }
                    //-----------------------------------------[END]---
                } else if(drawNotFocused)
Comment 20 Miloslav Metelka 2013-01-14 12:08:26 UTC
So the problem is that Graphics.setXORMode() does not work well on Retina displays. Thanks to all for the research.

Reassigning to platform/JDKIssues so that a JDK bug gets created for the problem.
Comment 21 Stanislav Aubrecht 2013-07-31 14:13:03 UTC
Reporter, please provide JDK and OS version info so that I can file a bug against JDK, thanks.
Comment 22 err 2013-07-31 14:37:41 UTC
CC'd charlestang, hope either he or shanepbrady can test recent versions of software (in particular jre 1.7). (I do not have access to a MAC Retina).

The first Retina OSX version and jre1.6 have the problem.

Note that the source of the problem has been tracked down to Graphics.setXORMode()

BTW, recent jVi releases provides a workaround with the platform option
    Mac Retina Cursor Xor Bug
So jVi users on Retina can toggle this option to see the results. (changing the option should not require a restart)


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo