RichEdit 8 Zoom Support

In this day and age with touch pinch and expand zooming of screens, zoom is everywhere! So you might wonder how to zoom the contents of a RichEdit control. There are two ways: 1) maintaining the display width and rewrapping the text as necessary to fill the client rectangle, and 2) zooming everything including the display width. The first way can be called rewrapped zoom and is enabled by sending an EM_SETZOOM message or by providing an appropriate display height in the ITextHost::TxGetExtent callback. Rewrapped zoom can be accomplished by RichEdit itself, requiring a minimum of host effort. It’s useful notably in that no panning is needed to read the text. For example, the Amazon Kindle offers rewrapped zoom to allow readers to view text at a larger size without panning.

The second way can be called unrewrapped zoom and has to be implemented in the host since the client RECT zooms along with the contents. This is the typical zoom method used on cell phones, tablets, and in many Windows applications such as OneNote and Word. It requires panning for larger zoom sizes when the text lines no longer fit within the window width. It uses a six-factor 2D transform and the host has to “unzoom” mouse coordinates so that RichEdit hit testing works correctly. For the traditional Windows GDI environment, the hosts sets the zoom factor by calling SetWorldTransform(). For the relatively new D2D environment, the host sets the zoom factor by calling ID2D1RenderTarget::SetTransform(). Both calls pass the same 2×3 transform matrix, although the matrices have different names. The host can also implement rewrapped zoom by unzooming the display width appropriately, although it’s easier to let RichEdit handle rewrapped zoom.

Up through RichEdit 8, both kinds of zoom work in GDI mode. In RichEdit 8, unrewrapped zoom works in D2D mode; earlier versions of RichEdit don’t have a D2D mode. RichEdit 8 doesn’t rerasterize images when the zoom factor changes, so images can become blurry even when they have high native resolution.

EM_SETZOOM provides the zoom numerator in wparam and the zoom denominator in lparam. Alternatively the numerator is given by the height returned by the ITextHost::TxGetClientRect() and the denominator by the vertical size returned by ITextHost::TxGetExtent. The latter is in HIMETRIC units (0.01 mm), and is converted to pixels for the zoom denominator. The zoom factor is incorporated into the horizontal and vertical display device resolution factors when GDI is being used to display text. These factors are set to EMUs per inch (914400/inch) for the D2D/DWrite mode, and hence RichEdit 8 doesn’t offer rewrapped zoom in D2D mode. Hopefully someday!