From c04212f5385439f9b3ee411972fc867d2aaf28aa Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Fri, 17 Dec 2010 09:10:33 -0700 Subject: [PATCH] specially record transparent-canvas drawing for a small number of drawing ops which enables background-sensitive smoothing of text original commit: f700a15d854b9154bba5518a5c3e1c2367508b52 --- collects/mred/private/wx/cocoa/dc.rkt | 11 +--- .../mred/private/wx/common/backing-dc.rkt | 56 ++++++++++++++++++- collects/mred/private/wx/gtk/dc.rkt | 11 +--- collects/mred/private/wx/win32/dc.rkt | 11 +--- collects/scribblings/gui/canvas-class.scrbl | 5 +- collects/scribblings/gui/canvas-intf.scrbl | 42 ++++++++------ .../scribblings/gui/editor-canvas-class.scrbl | 4 +- 7 files changed, 91 insertions(+), 49 deletions(-) diff --git a/collects/mred/private/wx/cocoa/dc.rkt b/collects/mred/private/wx/cocoa/dc.rkt index b739fa88..2984ec5f 100644 --- a/collects/mred/private/wx/cocoa/dc.rkt +++ b/collects/mred/private/wx/cocoa/dc.rkt @@ -27,7 +27,7 @@ (define canvas cnvs) (inherit end-delay) - (super-new) + (super-new [transparent? (not (send canvas get-canvas-background))]) (define gl #f) (define/override (get-gl-context) @@ -89,13 +89,6 @@ (let* ([surface (cairo_quartz_surface_create_for_cg_context cg (unbox w) (unbox h))] [cr (cairo_create surface)]) (cairo_surface_destroy surface) - (let ([s (cairo_get_source cr)]) - (cairo_pattern_reference s) - (cairo_set_source_surface cr (send bm get-cairo-surface) 0 0) - (cairo_new_path cr) - (cairo_rectangle cr 0 0 (unbox w) (unbox h)) - (cairo_fill cr) - (cairo_set_source cr s) - (cairo_pattern_destroy s)) + (backing-draw-bm bm cr (unbox w) (unbox h)) (cairo_destroy cr)))))) (tellv ctx restoreGraphicsState))) diff --git a/collects/mred/private/wx/common/backing-dc.rkt b/collects/mred/private/wx/common/backing-dc.rkt index f6c9b3b5..d095a881 100644 --- a/collects/mred/private/wx/common/backing-dc.rkt +++ b/collects/mred/private/wx/common/backing-dc.rkt @@ -4,11 +4,14 @@ racket/draw/private/bitmap-dc racket/draw/private/bitmap racket/draw/private/local + racket/draw/private/record-dc + racket/draw/unsafe/cairo "../../lock.rkt" "queue.rkt") (provide (protect-out backing-dc% + backing-draw-bm ;; scoped method names: get-backing-size @@ -35,13 +38,19 @@ end-delay) (define backing-dc% - (class (dc-mixin bitmap-dc-backend%) + (class (record-dc-mixin (dc-mixin bitmap-dc-backend%)) + (init transparent?) + (inherit internal-get-bitmap internal-set-bitmap - reset-cr) + reset-cr + set-recording-limit + get-recorded-command) (super-new) + (set-recording-limit (if transparent? 1024 -1)) + (define/override (ok?) #t) ;; Override this method to get the right size @@ -67,7 +76,8 @@ [(not retained-cr) #f] [(positive? retained-counter) (unless nada? - (proc (internal-get-bitmap))) + (proc (or (get-recorded-command) + (internal-get-bitmap)))) #t] [else (reset-backing-retained proc) @@ -155,3 +165,43 @@ (define (release-backing-bitmap bm) (send bm release-bitmap-storage)) + +(define cairo-dc + (make-object (dc-mixin + (class default-dc-backend% + (inherit reset-cr) + + (define cr #f) + (define w 0) + (define h 0) + + (super-new) + + (define/public (set-cr new-cr new-w new-h) + (set! cr new-cr) + (set! w new-w) + (set! h new-h) + (when cr + (reset-cr cr))) + + (define/override (get-cr) cr) + + (define/override (reset-clip cr) + (super reset-clip cr) + (cairo_rectangle cr 0 0 w h) + (cairo_clip cr)))))) + +(define (backing-draw-bm bm cr w h) + (if (procedure? bm) + (begin + (send cairo-dc set-cr cr w h) + (bm cairo-dc) + (send cairo-dc set-cr #f 0 0)) + (let ([s (cairo_get_source cr)]) + (cairo_pattern_reference s) + (cairo_set_source_surface cr (send bm get-cairo-surface) 0 0) + (cairo_new_path cr) + (cairo_rectangle cr 0 0 w h) + (cairo_fill cr) + (cairo_set_source cr s) + (cairo_pattern_destroy s)))) diff --git a/collects/mred/private/wx/gtk/dc.rkt b/collects/mred/private/wx/gtk/dc.rkt index ed66511f..76128592 100644 --- a/collects/mred/private/wx/gtk/dc.rkt +++ b/collects/mred/private/wx/gtk/dc.rkt @@ -96,7 +96,7 @@ (inherit end-delay) (define canvas cnvs) - (super-new) + (super-new [transparent? (not (send canvas get-canvas-background))]) (define gl #f) (define/override (get-gl-context) @@ -146,12 +146,5 @@ [h (box 0)]) (send canvas get-client-size w h) (let ([cr (gdk_cairo_create win)]) - (let ([s (cairo_get_source cr)]) - (cairo_pattern_reference s) - (cairo_set_source_surface cr (send bm get-cairo-surface) 0 0) - (cairo_new_path cr) - (cairo_rectangle cr 0 0 (unbox w) (unbox h)) - (cairo_fill cr) - (cairo_set_source cr s) - (cairo_pattern_destroy s)) + (backing-draw-bm bm cr (unbox w) (unbox h)) (cairo_destroy cr)))))) diff --git a/collects/mred/private/wx/win32/dc.rkt b/collects/mred/private/wx/win32/dc.rkt index db260240..b561e8f5 100644 --- a/collects/mred/private/wx/win32/dc.rkt +++ b/collects/mred/private/wx/win32/dc.rkt @@ -67,7 +67,7 @@ (inherit end-delay) (define canvas cnvs) - (super-new) + (super-new [transparent? (not (send canvas get-canvas-background))]) (define gl #f) (define/override (get-gl-context) @@ -116,14 +116,7 @@ (let* ([surface (cairo_win32_surface_create hdc)] [cr (cairo_create surface)]) (cairo_surface_destroy surface) - (let ([s (cairo_get_source cr)]) - (cairo_pattern_reference s) - (cairo_set_source_surface cr (send bm get-cairo-surface) 0 0) - (cairo_new_path cr) - (cairo_rectangle cr 0 0 (unbox w) (unbox h)) - (cairo_fill cr) - (cairo_set_source cr s) - (cairo_pattern_destroy s)) + (backing-draw-bm cr bm (unbox w) (unbox h)) (cairo_destroy cr)))))) (define (request-flush-delay canvas) diff --git a/collects/scribblings/gui/canvas-class.scrbl b/collects/scribblings/gui/canvas-class.scrbl index be13bbe9..43d1da29 100644 --- a/collects/scribblings/gui/canvas-class.scrbl +++ b/collects/scribblings/gui/canvas-class.scrbl @@ -55,8 +55,9 @@ The @scheme[style] argument indicates one or more of the following styles: canvas before calls to @method[canvas% on-paint]} @item{@scheme['transparent] --- the canvas is automatically ``erased'' - before an update using it's parent window's background; the result is - undefined if this flag is combined with @scheme['no-autoclear]} + before an update using it's parent window's background; see @racket[canvas<%>] + for information on the interaction of @racket['transparent] and offscreen buffering; + the result is undefined if this flag is combined with @scheme['no-autoclear]} @item{@scheme['no-focus] --- prevents the canvas from accepting the keyboard focus when the canvas is clicked, or when the diff --git a/collects/scribblings/gui/canvas-intf.scrbl b/collects/scribblings/gui/canvas-intf.scrbl index e802de77..411d9b8f 100644 --- a/collects/scribblings/gui/canvas-intf.scrbl +++ b/collects/scribblings/gui/canvas-intf.scrbl @@ -6,9 +6,6 @@ A canvas is a subwindow onto which graphics and text can be drawn. Canvases also receive mouse and keyboard events. -To draw onto a canvas, get its device context (see -@method[canvas<%> get-dc]). - The @scheme[canvas<%>] interface is implemented by two classes: @itemize[ @@ -20,6 +17,28 @@ The @scheme[canvas<%>] interface is implemented by two classes: ] +To draw onto a canvas, get its device context (see +@method[canvas<%> get-dc]). + +Drawing to a canvas's drawing context actually renders into an +offscreen buffer. The buffer is automatically flushed to the screen by +a background thread, explicitly via the @method[canvas<%> flush] +method, or explicitly via @racket[flush-display]---unless flushing +has been disabled for the canvas. The @method[canvas<%> +suspend-flush] method suspends flushing for a canvas until a matching +@method[canvas<%> resume-flush] calls; calls to @method[canvas<%> +suspend-flush] and @method[canvas<%> resume-flush] can be nested, in +which case flushing is suspended until the outermost @method[canvas<%> +suspend-flush] is balanced by a @method[canvas<%> resume-flush]. + +In the case of a transparent canvas (i.e., one that is created with +@racket['transparent] style), line and text smoothing can depend on +the window that serves as the canvas's background. For example, +smoothing may color pixels differently depending on whether the target +context is white or gray. Background-sensitive smoothing is supported +only if a relatively small number of drawing commands are recorded in +the canvas's offscreen buffer, however. + @defmethod*[([(accept-tab-focus) boolean?] @@ -191,7 +210,7 @@ Does nothing. @defmethod[(resume-flush) void?]{ -See @method[canvas<%> suspend-flush].} +See @racket[canvas<%>] for information on canvas flushing.} @@ -223,19 +242,10 @@ Under Mac OS X, enables or disables space for a resize tab at the @defmethod[(suspend-flush) void?]{ -Drawing to a canvas's drawing context actually renders into an -offscreen buffer. The buffer is automatically flushed to the screen by -a background thread, explicitly via the @method[canvas<%> flush] method, -or explicitly via @racket[flush-display] --- unless flushing has been disabled for the canvas. -The @method[canvas<%> suspend-flush] method suspends flushing for a -canvas until a matching @method[canvas<%> resume-flush] calls; calls to -@method[canvas<%> suspend-flush] and @method[canvas<%> resume-flush] can -be nested, in which case flushing is suspended until the outermost -@method[canvas<%> suspend-flush] is balanced by a @method[canvas<%> -resume-flush]. +See @racket[canvas<%>] for information on canvas flushing. -On some platforms, beware that suspending flushing for a canvas can -discourage refreshes for other windows in the same frame.} +Beware that suspending flushing for a canvas can discourage refreshes +for other windows in the same frame on some platforms.} @defmethod[(warp-pointer [x (integer-in 0 10000)] diff --git a/collects/scribblings/gui/editor-canvas-class.scrbl b/collects/scribblings/gui/editor-canvas-class.scrbl index f0bf8589..4b6e24bd 100644 --- a/collects/scribblings/gui/editor-canvas-class.scrbl +++ b/collects/scribblings/gui/editor-canvas-class.scrbl @@ -71,7 +71,9 @@ The @scheme[style] list can contain the following flags: method} @item{@scheme['transparent] --- the canvas is ``erased'' before an - update using its parent window's background} + update using its parent window's background; see @racket[canvas<%>] + for information on the interaction of @racket['transparent] and + offscreen buffering} ]