The focus rectangle says, “I’m not orange. I’m just drawn that way.”

Raymond

A customer saw that the Draw­Focus­Rect function was drawing an orange focus rectangle when applied to highlighted text. Whose bright idea was it for the focus rectangle to be orange?

The focus rectangle says, “I’m not orange. I’m just drawn that way.”

The focus rectangle is drawn by performing an XOR operation with a checkerboard brush. The idea behind using an XOR brush was that you could erase the focus rectangle by drawing it again. And the checkerboard brush means that both horizontal and vertical lines are dotted, and the corners match.

Rewind back to 1983. Most computer screens were monochrome. Bitmaps were one bit per pixel. And screens were 96 DPI.

In this world, XOR is a perfectly reasonable thing to do, since it looks good against both white¹ and black backgrounds.

A simple pattern of alternating white and black pixels gets you the dotted-line effect.

Of course, weird things happened if the focus rectangle was drawn against a non-solid background, but given the limitations of the hardware, you didn’t really have too much choice.

Fast-forward to the days of high-density 32-bit-per-pixel displays. That simple algorithm doesn’t produce results that are quite so pretty any more. For one thing, a single pixel dotted line is barely visible on high-density displays. And for another thing, XOR’ing colored pixels can produce strange effects.

In our case, what happened is that we took the blue color #0078D7 and flipped all the bits, producing #FF8728, which is bright orange.

That’s where the orange comes from. The focus rectangle doesn’t draw orange. It just flips the pixels that are already there, and blue flips to orange.

The Draw­Focus­Rect function can’t do anything about the XOR brush, because that would break compatibility with code that used a second Draw­Focus­Rect to erase the focus rectangle. But at least it can do a little bit to help with the dotted rectangle: The thickness of the dotted rectangle is controlled by an accessibility setting. In Control Panel, under Ease of Access, Make the computer easier to see, you can check “Make the focus rectangle thicker”, which makes the focus rectangle two pixels thick instead of just being a dotted line.

Programs which draw their own focus indicators can match the accessibility setting by using the SPI_GET­FOCUS­BORDER­WIDTH and SPI_GET­FOCUS­BORDER­HEIGHT system metrics.

Bonus chatter: The blinking line that indicates where typing will be inserted is called the caret, and it too is drawn by XOR. This works fine when the caret is against a white or black background, but again, if it’s against a colored background, things can get a little weird.

¹ Or, more likely, P1 phosphor green and black, or P3 phosphor amber and black.

8 comments

Leave a comment

  • ChDF T

    The idea behind using an XOR brush was that you could erase the focus rectangle by drawing it again.

    This explains a lot. Back in the days when everyone used GDI+ and liked it, these highlight rectangles would sporadically only get partially removed¹. It never occurred to me, that the application might be relying on the XOR-nature instead of redrawing the entire window (or part of it).
    This brings me to the hypothesis, that when this issue occurs the following happens: 1) draw rectangle of size x; 2) internal application state changes, so that the size of the rectangle is no longer correctly stored; 3) erase rectangle x by drawing the rectangle “again”, but with incorrect size y -> resulting in partial ghost rectangles (everywhere where x and y did not overlap)

    That simple algorithm doesn’t produce results that are quite so pretty any more.

    On the other hand, it has some accessibility advantages: the color-inversion is usually² easily discernible no matter the base-image content (a more modern explorer-style blue outline+background can be hard to see on mostly blue base-images). This even works if the user is color-blind, as the color inversion ensures that all color-components change.

    ¹ If I remember correctly, this problem was more common when the brush was used to draw a selection rectangle (like the “select” tool in Paint).
    ² There is obviously the edge case where the base-image contains a pattern of inverted colors, which make the resulting dotted line hard to see. Such images are probably rather rare.

      • ChDF T

        That is a very good point. The 50ish% gray as an edge-case isn’t even all that rare either.
        And since the XORing nature – and not just the 2nd-call-reverts-changes-nature – is actually documented, DrawFocusRect can’t even be changed to use some other mapping where ∀c: map(map(c))=c (which would at least enable the graphics designers to choose pairs of colors which look less odd than blue-orange and are more visible than gray-gray).

        • Neil Rashbrook

          Ah, but it can – simply XOR with 50% grey, 0x7F7F7F if you want colour inversion, 0x808080 if you don’t. In at least Windows 95-2000 you also used to be able to do this with the mouse cursor, but of course this was undocumented behaviour and sadly stopped working in Windows XP.

          • Antonio Rodríguez

            XORing a 50% grey with white, black or any saturated color gives a 50% grey, which may not have enough contrast. And with a non-saturated color (dark, pastel, grayed, etc.) is even worse: it gives the an opposite color, yes, but with a value (luminance) dangerously near to the original (a purple dotted line on a medium green background, for example). It is a bad idea, specially when you take accessibility into account. See my comment bellow for a more detailed explanation on why this happens.

          • Neil Rashbrook

            Actually, 0x7F7F7F doesn’t work on light grey 0xC0C0C0 because it just turns it into 0xBFBFBF so forget that. As for 0x808080, it does at least guarantee exactly 50% contrast on all grey backgrounds, but I can’t remember how it looks like on coloured backgrounds, although I do remember it being dim and so I understand it wouldn’t suit everyone.

      • Antonio Rodríguez

        You should never use mid values (i.e. 50% gray) as background when information is going to be placed on it. Human vision is far more sensitive to luminance than to chrominance, so the best way to make something readable is either dark text (or pictures) on clear background, or clear text (or pictures) on dark background. This is also why, for example, yellow on white, or navy blue on black, are really hard to read. Using good luminance contrast has the added benefit that it makes the design safe for every kind of color blindness, since you are not relying on color to convey information. As a rule of thumb, I reject any design where the difference between background and foreground luminances is less than 60% (which automatically rules out any background in the 40-60% region, including the 50% gray).

        Sadly, fashions come and go, and far too frequently graphics designers disregards those basics in the name of the current trend. Like now, when the latest stupid fashion is placing light gray text on white background, which makes it difficult to read for anyone, and almost impossible for people over 50 or with vision problems.