1 ;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: CLOSURE/CLIM-DEVICE; -*-
2 ;;; ---------------------------------------------------------------------------
3 ;;; Title: CLIM device for the renderer
5 ;;; Author: Gilbert Baumann <gilbert@base-engineering.com>
6 ;;; License: MIT style (see below)
7 ;;; ---------------------------------------------------------------------------
8 ;;; (c) copyright 2005 by Gilbert Baumann
10 ;;; Permission is hereby granted, free of charge, to any person obtaining
11 ;;; a copy of this software and associated documentation files (the
12 ;;; "Software"), to deal in the Software without restriction, including
13 ;;; without limitation the rights to use, copy, modify, merge, publish,
14 ;;; distribute, sublicense, and/or sell copies of the Software, and to
15 ;;; permit persons to whom the Software is furnished to do so, subject to
16 ;;; the following conditions:
18 ;;; The above copyright notice and this permission notice shall be
19 ;;; included in all copies or substantial portions of the Software.
21 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 ;;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 ;;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 ;;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 ;;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 (in-package :CLOSURE
/CLIM-DEVICE
)
31 (defclass clim-device
()
32 ((medium :accessor clim-device-medium
:initarg
:medium
)
33 (font-database :initform nil
)
34 (zoom-factor :initform gui
:*zoom-factor
* :initarg
:zoom-factor
)))
36 (defmethod device-dpi ((device clim-device
))
37 (with-slots (zoom-factor) device
38 (* (graft-pixels-per-inch (graft (clim-device-medium device
)))
41 (defmethod device-font-ascent ((device clim-device
) font
)
42 (text-style-ascent font
(clim-device-medium device
))
45 (defmethod device-font-descent ((device clim-device
) font
)
46 (text-style-descent font
(clim-device-medium device
))
49 (defmethod device-font-underline-position ((self clim-device
) font
)
53 (defmethod device-font-underline-thickness ((self clim-device
) font
)
57 (defmethod device-font-has-glyph-p ((self clim-device
) font code-point
)
58 (<= 0 code-point
255) ;hmm
61 (defresource one-character-string
(char)
62 :constructor
(make-string 1)
63 :initializer
(setf (aref one-character-string
0) char
)
66 (defmethod device-font-glyph-width ((self clim-device
) font code-point
)
67 (using-resource (string one-character-string
(code-char code-point
))
68 (text-size (clim-device-medium self
) string
:text-style font
)))
70 (defmethod scale-font-desc ((self clim-device
) font-desc size
)
73 (defmethod device-realize-font-desc ((self clim-device
) font-desc
)
74 (font-desc-ddp font-desc
))
76 (defmethod device-font-database ((self clim-device
))
77 (with-slots (font-database) self
80 (let ((fdb (make-font-database ;xxx
81 :cache
(make-hash-table :test
#'equal
)
84 for family in
'("Times" "Helvetica" "Courier")
85 for clim-family in
'(:serif
:sans-serif
:fix
)
86 for size-adjust in
'(-2 -
2 -
2) do
88 for weight
+style in
'((400 :normal
) (400 :italic
) (700 :normal
) (700 :italic
))
89 for clim-face in
'(:roman
:italic
:bold
(:bold
:italic
)) do
91 for size in
'(8 10 12 14 18 24) do
92 (font-database-relate fdb
95 :weight
(first weight
+style
)
96 :style
(second weight
+style
)
97 :size
(+ size size-adjust
)
98 :ddp
(make-text-style clim-family clim-face size
)
99 :charset
(ws/charset
:find-charset
:iso-8859-1
) ;xxx
103 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
105 (defmethod scale-font-desc ((self clim-device
) font-desc size
)
106 (let ((r (r2::copy-font-desc font-desc
)))
108 (if (eql (nth-value 0 (text-style-components (font-desc-ddp r
)))
112 (setf (font-desc-size r
) size
113 (font-desc-ddp r
) (make-text-style (nth-value 0 (text-style-components (font-desc-ddp r
)))
114 (nth-value 1 (text-style-components (font-desc-ddp r
)))
118 (defmethod device-realize-font-desc ((self clim-device
) font-desc
)
119 (font-desc-ddp font-desc
))
121 (defmethod device-font-database ((self clim-device
))
122 (with-slots (font-database) self
125 (let ((fdb (make-font-database ;xxx
126 :cache
(make-hash-table :test
#'equal
)
129 for family in
'("Times" "Helvetica" "Courier")
130 for clim-family in
'(:serif
:sans-serif
:fix
)
131 for size-adjust in
'(-2 0 -
2) do
133 for weight
+style in
'((400 :normal
) (400 :italic
) (700 :normal
) (700 :italic
))
134 for clim-face in
'(:roman
:italic
:bold
(:bold
:italic
)) do
135 (font-database-relate fdb
138 :weight
(first weight
+style
)
139 :style
(second weight
+style
)
141 :ddp
(make-text-style clim-family clim-face
12)
142 :charset
(ws/charset
:find-charset
:iso-8859-1
) ;xxx
147 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
150 (defparameter *buffer
* (make-array 1000))
152 (defun resolve-background-position (spec image-dim box-dim
)
153 (cond ((css:percentage-p spec
)
154 (let ((i (r2::maybe-resolve-percentage spec image-dim
))
155 (b (r2::maybe-resolve-percentage spec box-dim
)))
158 (warn "~S: null spec." 'resolve-background-position
)
163 ;; newer definition below
164 ;;;(defun background-pixmap+mask (document drawable bg)
165 ;;; (cond ((r2::background-%pixmap bg)
166 ;;; (values (r2::background-%pixmap bg)
167 ;;; (r2::background-%mask bg)))
169 ;;; (setf (r2::background-%pixmap bg) :none)
170 ;;; (funcall ;;r2::run-process-on-behalf-of-document document
172 ;;; (let ((aimage (clue-gui2::aimage-from-url document (r2::background-image bg))))
173 ;;; (cond ((eq aimage :error)
174 ;;; (setf (r2::background-%pixmap bg) :none)
175 ;;; (values (r2::background-%pixmap bg)
176 ;;; (r2::background-%mask bg)))
178 ;;; (let ((pm (ws/x11::aimage->pixmap+mask drawable aimage)))
179 ;;; (setf (r2::background-%pixmap bg) (car pm)
180 ;;; (r2::background-%mask bg) (cadr pm))
182 ;;; (clue-gui2::gui-post
184 ;;; ;; we do it the hard way via an exposure round trip.
187 ;;; :exposures-p t))))))
188 ;;; ;;:name "Lazy Document background fetch."
190 ;;; (values (r2::background-%pixmap bg)
191 ;;; (r2::background-%mask bg)))))
193 ;; apparently unused --dfl
194 ;;;(defmethod update-lazy-object (document (self null))
197 (defun map-region-rectangles (fun region
)
198 (clim:map-over-region-set-regions
200 (apply fun
(mapcar #'round
201 (multiple-value-list (clim:rectangle-edges
* r
)))))
203 :normalize
:y-banding
))
205 (defun region-to-x11-rectangle-list (region)
207 (map-region-rectangles (lambda (x1 y1 x2 y2
)
213 (mapcar #'round res
)))
215 (defun region-from-x11-rectangle-list (rectangle-sequence)
216 (let ((res clim
:+nowhere
+))
217 (do ((q rectangle-sequence
(nthcdr 4 q
)))
219 (setf res
(region-union res
220 (make-rectangle* (first q
) (second q
)
221 (+ (first q
) (third q
))
222 (+ (second q
) (fourth q
))))))
225 ;; apparently unused --dfl
227 ;;;(defun background-pixmap+mask (document drawable bg)
228 ;;; (cond ((r2::background-%pixmap bg)
230 ;;; (values (r2::background-%pixmap bg)
231 ;;; (r2::background-%mask bg)))
233 ;;; (let ((aimage #+NIL(r2::document-fetch-image document nil (r2::background-image bg))
234 ;;; (r2::url->aimage document (r2::background-image bg) nil)
236 ;;; ;; arg, jetzt haben wir wieder broken images
237 ;;; (cond ((eql nil aimage)
240 ;;; (cond ((eq aimage :error)
241 ;;; (setf (r2::background-%pixmap bg) :none) )
243 ;;; (let ((pm (ws/x11::aimage->pixmap+mask drawable aimage)))
244 ;;; (setf (r2::background-%pixmap bg) (car pm)
245 ;;; (r2::background-%mask bg) (cadr pm)))))
246 ;;; (values (r2::background-%pixmap bg)
247 ;;; (r2::background-%mask bg)))))) ))
249 (defun ws/x11
::x11-put-pixmap-tiled
(drawable ggc pixmap mask x y w h
&optional
(xo 0) (yo 0))
250 (cond ((null mask
) ;; xxx
251 (xlib:with-gcontext
(ggc :exposures
:off
256 ;;mask wird momentan noch ignoriert!
257 (xlib:draw-rectangle drawable ggc x y w h t
)))
259 (let* ((old-clip-mask (car (or (ignore-errors (list (xlib:gcontext-clip-mask ggc
)))
261 (clip-region (let ((q old-clip-mask
))
263 (region-from-x11-rectangle-list q
)
265 (paint-region (region-intersection
267 (make-rectangle* x y
(+ x w
) (+ y h
)))) )
268 ;; There is a bug in CLX wrt to clip-x / clip-y
269 ;; Turning off caching helps
270 (setf (xlib:gcontext-cache-p ggc
) nil
)
272 ;; we have to do our own clipping here.
273 (let ((iw (xlib:drawable-width pixmap
))
274 (ih (xlib:drawable-height pixmap
)))
275 (loop for i from
(floor (- x xo
) iw
) to
(ceiling (- (+ x w
) (+ xo iw
)) iw
)
277 (loop for j from
(floor (- y yo
) ih
) to
(ceiling (- (+ y h
) (+ yo ih
)) ih
)
279 (let ((rect (make-rectangle*
282 (+ (+ xo
(* i iw
)) iw
)
283 (+ (+ yo
(* j ih
)) ih
))))
284 (map-region-rectangles
285 (lambda (rx0 ry0 rx1 ry1
)
286 (xlib:with-gcontext
(ggc :exposures
:off
290 :clip-x
(+ xo
(* i iw
))
291 :clip-y
(+ yo
(* j ih
))
294 (xlib:draw-rectangle drawable ggc
295 rx0 ry0
(max 0 (- rx1 rx0
)) (max 0 (- ry1 ry0
))
297 (region-intersection paint-region rect
))))) )
298 ;; turn on caching again (see above)
299 (setf (xlib:gcontext-cache-p ggc
) t
)
301 ;; and xlib:with-gcontext also is broken!
302 (setf (xlib:gcontext-clip-mask ggc
) old-clip-mask
)))))
306 #+:CMU
`(eval ',x
) ;compiler bug
308 '(defun ws/x11
::x11-put-pixmap-tiled
(drawable ggc pixmap mask x y w h
&optional
(xo 0) (yo 0))
309 (cond ((null mask
) ;; xxx
310 (xlib:with-gcontext
(ggc :exposures
:off
315 ;;mask wird momentan noch ignoriert!
316 (xlib:draw-rectangle drawable ggc x y w h t
)))
318 (let* ((old-clip-mask (car (or (ignore-errors (list (xlib:gcontext-clip-mask ggc
)))
320 (clip-region (let ((q old-clip-mask
))
322 (region-from-x11-rectangle-list q
)
324 (paint-region (region-intersection
326 (make-rectangle* x y
(+ x w
) (+ y h
)))) )
327 ;; There is a bug in CLX wrt to clip-x / clip-y
328 ;; Turning off caching helps
329 (setf (xlib:gcontext-cache-p ggc
) nil
)
331 ;; we have to do our own clipping here.
332 (let ((iw (xlib:drawable-width pixmap
))
333 (ih (xlib:drawable-height pixmap
)))
334 (loop for i from
(floor (- x xo
) iw
) to
(ceiling (- (+ x w
) (+ xo iw
)) iw
)
336 (loop for j from
(floor (- y yo
) ih
) to
(ceiling (- (+ y h
) (+ yo ih
)) ih
)
338 (let ((rect (make-rectangle*
341 (+ (+ xo
(* i iw
)) iw
)
342 (+ (+ yo
(* j ih
)) ih
))))
343 (map-region-rectangles
344 (lambda (rx0 ry0 rx1 ry1
)
345 (xlib:with-gcontext
(ggc :exposures
:off
349 :clip-x
(+ xo
(* i iw
))
350 :clip-y
(+ yo
(* j ih
))
353 (xlib:draw-rectangle drawable ggc
354 rx0 ry0
(max 0 (- rx1 rx0
)) (max 0 (- ry1 ry0
))
356 (region-intersection paint-region rect
))))) )
357 ;; turn on caching again (see above)
358 (setf (xlib:gcontext-cache-p ggc
) t
)
360 ;; and xlib:with-gcontext also is broken!
361 (setf (xlib:gcontext-clip-mask ggc
) old-clip-mask
))))))
363 ;; apparently unused --dfl
365 ;;;(defun x11-draw-background (document medium bg x y width height
366 ;;; &optional (bix x) (biy y) (biwidth width) (biheight height))
369 ;;; ;; (unless (eql (background-color bg) :transparent)
370 ;;; ;; (ws/x11::fill-rectangle* drawable gcontext
371 ;;; ;; (round x) (round y)
372 ;;; ;; (max 0 (round width))
373 ;;; ;; (max 0 (round height))
374 ;;; ;; (background-color bg)) )
375 ;;; (unless (eql (r2::background-image bg) :none)
376 ;;; (multiple-value-bind (pixmap mask)
377 ;;; (background-pixmap+mask document (sheet-direct-mirror (medium-sheet medium)) bg)
378 ;;; #+emarsden2005-07-15
379 ;;; (print (list 'x11-draw-background pixmap mask))
380 ;;; (unless (eql pixmap :none)
381 ;;; (let* ((iw (xlib:drawable-width pixmap))
382 ;;; (ih (xlib:drawable-height pixmap))
383 ;;; (w (ecase (r2::background-repeat bg)
384 ;;; ((:repeat :repeat-x) width)
385 ;;; ((:no-repeat :repeat-y) iw)))
386 ;;; (h (ecase (r2::background-repeat bg)
387 ;;; ((:repeat :repeat-y) height)
388 ;;; ((:no-repeat :repeat-x) ih))) )
389 ;;; (let ((hp (car (r2::background-position bg)))
390 ;;; (vp (cdr (r2::background-position bg))))
391 ;;; (let ((xo (+ bix (resolve-background-position hp iw biwidth)))
392 ;;; (yo (+ biy (resolve-background-position vp ih biheight))))
393 ;;; (medium-draw-pm3-tiled* medium pixmap mask
394 ;;; (round (ecase (r2::background-repeat bg)
395 ;;; ((:repeat :repeat-x) x)
396 ;;; ((:no-repeat :repeat-y) (+ xo))))
397 ;;; (round (ecase (r2::background-repeat bg)
398 ;;; ((:repeat :repeat-y) y)
399 ;;; ((:no-repeat :repeat-x) (+ yo))))
400 ;;; (round w) (round h)
401 ;;; (round (+ xo)) (round (+ yo)))))) ))) ))
403 ;;;; --------------------------------------------------------------------------------
408 (actual-width :initarg
:actual-width
410 :documentation
"The actual (scaled) width of this image.")
411 (actual-height :initarg
:actual-height
413 :documentation
"The actual (scaled) height of this image.")
414 (design :initform nil
)))
416 (defmethod gui::deconstruct-robj
((self ro
/img
))
417 ;; no deconstructor for now ...
420 (defmethod r2:ro
/intrinsic-size
((self ro
/img
)) ;; -> width; height; depth
421 (with-slots (aim) self
422 (values (r2::aimage-width aim
)
423 (r2::aimage-height aim
)
426 (defmethod r2:ro
/size
((self ro
/img
));; -> width; height; depth
427 (with-slots (aim actual-width actual-height
) self
428 (values (or actual-width
(r2::aimage-width aim
))
429 (or actual-height
(r2::aimage-height aim
))
432 (defmethod r2:ro
/resize
((self ro
/img
) new-width new-height
)
433 (with-slots (actual-width actual-height
) self
434 (setf actual-width new-width
435 actual-height new-height
)))
437 (defmethod gui::make-image-replacement
((device clim-device
) document
&key url width height
)
439 (cond (nil (and width height
)
440 ;; when width and height are known, we do not bother to fetch
444 (setf aim
(r2::url-
>aimage document url
))
445 (when (eql aim
:error
)
446 (setf aim
(renderer::broken-aimage document
)))))
447 (make-instance 'ro
/img
450 :actual-width
(or width
(r2::aimage-width aim
))
451 :actual-height
(or height
(r2::aimage-height aim
)))))
453 (climi::def-grecording draw-ro
(() ro x y
) ()
455 (- y
(nth-value 1 (r2::ro
/size ro
)))
456 (+ x
(nth-value 0 (r2::ro
/size ro
)))
458 (climi::def-graphic-op draw-ro
(ro x y
))
460 (defun draw-ro* (sheet ro x y
&rest args
)
461 (climi::with-medium-options
(sheet args
)
462 (medium-draw-ro* medium ro x y
)))
465 (defmethod medium-draw-ro* ((medium clim
:medium
) (self ro
/img
) x y
)
468 (with-slots (aim design actual-width actual-height
) self
469 (when aim
;only draw something, if the image is already there.
471 (when (and actual-width actual-height
(not design
)) ;xxx
473 (clue-gui2::make-design-from-aimage medium
475 (max 1 (round actual-width
))
476 (max 1 (round actual-height
)))))
477 (climi::medium-draw-image-design
* medium design x y
))))
479 ;; apparently unused --dfl
481 ;;;(climi::def-grecording draw-pm3-tiled (() pixmap mask x1 y1 w h x0 y0)
482 ;;; (values x1 y1 (+ x1 w) (+ y1 h)))
484 ;;;(defmethod medium-draw-pm3-tiled* (medium pixmap mask x1 y1 w h x0 y0)
485 ;;; (let* ((da (sheet-direct-mirror (medium-sheet medium)))
487 ;;; (pixmap+mask (clue-gui2::make-pixmap-from-aimage da aim
488 ;;; (r2::aimage-width aim)
489 ;;; (r2::aimage-height aim)))
491 ;;; (pixmap (first pixmap+mask))
493 ;;; (mask (second pixmap+mask)))
494 ;;; (multiple-value-bind (x1 y1) (transform-position (sheet-device-transformation (medium-sheet medium))
496 ;;; (setf x1 (round x1))
497 ;;; (setf y1 (round y1))
499 ;;; (let ((gcontext (xlib:create-gcontext :drawable da)))
500 ;;; (ws/x11::x11-put-pixmap-tiled da gcontext pixmap mask x1 y1 w h x0 y0) ))))
504 (setf clim-clx
::*clx-text-family
+face-map
*
510 :bold-italic
"bold-o"
511 :italic-bold
"bold-o"))
517 :bold-italic
"bold-i"
518 :italic-bold
"bold-i"))
524 :bold-italic
"bold-i"
525 :italic-bold
"bold-i")) ))