When Scintilla handles a repaint it may first do some lexing and
wrapping to ensure that the text being drawn is correctly styled and
wrapped. These actions may reveal that additional areas need to be
drawn, such as when styling is more extensive than expected, possibly
because a multi-line construct like a comment has been inserted. To
see if more drawing will be needed, the extra changed text is checked
against the painting rectangle and if it is already about to be
painted then that wil be OK. If the area is outside the painting
rectangle then a full repaint is scheduled and the current paint is
abandoned.

   Unfortunately checking against the paint rectangle is inaccurate
when the paint is for an irregular region. This has led to the recent
bug where markers were being set in a modification handler leading to
complex shaped paint regions that included the margin and one line of
the text. When the modification was the creation or removal of a start
of a comment then other lines that should have been styled as a result
were not redrawn.

   This can be fixed by testing the area changed against the paint
region. On Windows, this can be achieved by making a copy of the
update region before calling BeginPaint and then performing the test
like this:

bool ScintillaWin::PaintContains(PRectangle rc) {
    bool contains = true;
    if (paintState == painting) {
        if (!rcPaint.Contains(rc)) {
            contains = false;
        } else {
            // In bounding rectangle so check more accurately using region
            HRGN hRgnRange = ::CreateRectRgn(rc.left, rc.top,
rc.right, rc.bottom);
            if (hRgnRange) {
                HRGN hRgnDest = ::CreateRectRgn(0, 0, 0, 0);
                if (hRgnDest) {
                    int combination = ::CombineRgn(hRgnDest,
hRgnRange, hRgnUpdate, RGN_DIFF);
                    if (combination != NULLREGION) {
                        contains = false;
                    }
                    ::DeleteRgn(hRgnDest);
                }
                ::DeleteRgn(hRgnRange);
            }
        }
    }
    return contains;
}

   PaintContains is a virtual method defined in Editor that can be
overridden by platform code to do whatever is needed for each
platform. On GTK+, the code looks like this:

bool ScintillaGTK::PaintContains(PRectangle rc) {
    bool contains = true;
    if (paintState == painting) {
        if (!rcPaint.Contains(rc)) {
            contains = false;
        } else {
            GdkRectangle grc = {rc.left, rc.top,
                rc.right - rc.left, rc.bottom - rc.top};
            if (gdk_region_rect_in(rgnUpdate, &grc) !=
GDK_OVERLAP_RECTANGLE_IN) {
                contains = false;
            }
        }
    }
    return contains;
}

   However, on GTK+ on X, a paint (referred to as an "expose") does
not clip drawing to the update region, so this is not really needed.
This is not what I expected but could be justified based on the
relative performance of clipping compared to just redrawing
everything. I can add a call to gdk_gc_set_clip_region but expect the
GTK+ developers know what they are doing.

   I'd like to know if the above approach can be implemented on all
the other platforms. If it can then I'll change Scintilla to use
PaintContains and platform developers can implement it.

   Neil

_______________________________________________
Scintilla-interest mailing list
[email protected]
http://mailman.lyra.org/mailman/listinfo/scintilla-interest

Reply via email to