/[cmucl]/src/clx/xrender.lisp
ViewVC logotype

Contents of /src/clx/xrender.lisp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show annotations)
Wed Jun 17 18:22:46 2009 UTC (4 years, 10 months ago) by rtoy
Branch: MAIN
CVS Tags: sparc-tramp-assem-base, post-merge-intl-branch, intl-branch-working-2010-02-19-1000, unicode-string-buffer-impl-base, release-20b-pre1, release-20b-pre2, unicode-string-buffer-base, sparc-tramp-assem-2010-07-19, amd64-dd-start, intl-2-branch-base, GIT-CONVERSION, cross-sol-x86-merged, intl-branch-working-2010-02-11-1000, RELEASE_20b, release-20a-base, cross-sol-x86-base, snapshot-2010-12, snapshot-2010-11, snapshot-2011-09, snapshot-2011-06, snapshot-2011-07, snapshot-2011-04, snapshot-2011-02, snapshot-2011-03, snapshot-2011-01, pre-merge-intl-branch, snapshot-2010-05, snapshot-2010-04, snapshot-2010-07, snapshot-2010-06, snapshot-2010-01, snapshot-2010-03, snapshot-2010-02, snapshot-2010-08, cross-sol-x86-2010-12-20, intl-branch-2010-03-18-1300, RELEASE_20a, release-20a-pre1, snapshot-2009-11, snapshot-2009-12, cross-sparc-branch-base, intl-branch-base, snapshot-2009-08, snapshot-2009-07, HEAD
Branch point for: cross-sparc-branch, RELEASE-20B-BRANCH, unicode-string-buffer-branch, sparc-tramp-assem-branch, RELEASE-20A-BRANCH, amd64-dd-branch, unicode-string-buffer-impl-branch, intl-branch, cross-sol-x86-branch, intl-2-branch
Changes since 1.1: +69 -45 lines
Merge portable-clx (2009-06-16) to main branch.  Tested by running
src/contrib/games/feebs and hemlock which works (in non-unicode
builds).
1 ;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: XLIB; -*-
2 ;;; ---------------------------------------------------------------------------
3 ;;; Title: The X Render Extension
4 ;;; Created: 2002-08-03
5 ;;; Author: Gilbert Baumann <unk6@rz.uni-karlsruhe.de>
6 #+cmu
7 (ext:file-comment "$Id: xrender.lisp,v 1.2 2009/06/17 18:22:46 rtoy Rel $")
8 ;;; ---------------------------------------------------------------------------
9 ;;;
10 ;;; (c) copyright 2002, 2003 by Gilbert Baumann
11 ;;; (c) copyright 2002 by Christian Sunesson
12 ;;;
13 ;;; Permission is granted to any individual or institution to use,
14 ;;; copy, modify, and distribute this software, provided that this
15 ;;; complete copyright and permission notice is maintained, intact, in
16 ;;; all copies and supporting documentation.
17 ;;;
18 ;;; This program is distributed in the hope that it will be useful,
19 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 ;;;
22
23 ;;; NOTE: we need to watch maximum request sizes and somehow work
24 ;;; around them. Sometimes e.g. in AddGlyphs this is not possible,
25 ;;; which is a design failure.
26
27 ;;; TODO
28
29 ;; - some request are still to be implemented at all.
30 ;; + Can they not wait? Xrender seems to be in flux as the specification
31 ;; isn't even conforming to the acctual protocol. However backwards
32 ;; wierd that sound. --noss
33
34 ;; - we need to invent something for the color values of e.g.
35 ;; fill-rectangles; I would prefer some generic functions, so that
36 ;; we later can map CLIM design directly to colors.
37
38 ;; - we want some conviencene function to turn graphics contexts into
39 ;; render pictures. --GB 2002-08-21
40
41 ;; - also: uniform-alpha-picture display alpha-value
42 ;; uniform-color-picture display red green blue
43 ;; --GB 2002-08-21
44
45 ;; - maybe we should aim for a higher level interface to
46 ;; color-trapzoids and color-triangles and offer a low level [raw]
47 ;; interface also for high performance apps?
48
49 ;; - Write tests.
50
51 ;;;; API issues
52
53 ;; - On one hand we want convenience functions like RENDER-TRIANGLE or
54 ;; WITH-UNIFORM-COLOR-PICTURE. On the other hand if you are up to
55 ;; write a full rasterization library you obviously want high
56 ;; performance entry points as RENDER-TRIANGLES-1.
57
58 ;; - We want to extend XLIB:COLOR into something with alpha channel.
59 ;; How to name it?
60
61 ;; - WITH-UNIFORM-COLOR-PICTURE (var picture r g b &optional alpha) &body body
62 ;;
63 ;; Example:
64 ;; (WITH-UNIFORM-COLOR-PICTURE (color dest 1.0 1.0 0.0)
65 ;; (RENDER-TRIANGLE dest color ...))
66
67 ;; - Pose the filter and the transform slots of a picture.
68
69 ;; - Also introduce a PICTURE-DEFAULT-MASK-FORMAT?
70
71 ;; - COPY-PICTURE?
72
73 ;; - WITH-PICTURE-OPTIONS ?
74 ;;
75 ;; (WITH-PICTURE-OPTIONS (pic :repeat :on) ...)
76
77 ;; - WITH-PICTURE ?
78 ;;
79 ;; (WITH-PICTURE (picture drawable ...) ...)
80
81 ;;
82
83 (in-package :xlib)
84
85 ;; Beginning to collect the external interface for documentation.
86 (export '(render-create-picture
87 render-free-picture
88
89 render-create-glyph-set
90 render-reference-glyph-set
91 render-free-glyph-set
92
93 render-add-glyph
94 render-add-glyph-from-picture
95 render-free-glyph
96 render-fill-rectangle
97
98 picture-format-display
99 picture-format-id
100 picture-format-type
101 picture-format-depth
102 picture-format-red-byte
103 picture-format-green-byte
104 picture-format-blue-byte
105 picture-format-alpha-byte
106 picture-format-colormap
107
108 ;; picture object
109 picture-repeat
110 picture-alpha-map
111 picture-alpha-x-origin
112 picture-alpha-y-origin
113 picture-clip-x-origin
114 picture-clip-y-origin
115 picture-clip-mask
116 picture-graphics-exposures
117 picture-subwindow-mode
118 picture-poly-edge
119 picture-poly-mode
120 picture-dither
121 picture-component-alpha
122 picture-drawable
123
124 find-matching-picture-formats
125 find-window-picture-format
126 render-free-picture
127 render-free-glyph-set
128 render-query-version
129 ;; render-query-picture-formats
130 render-fill-rectangle
131 render-composite
132 render-create-glyph-set
133 render-reference-glyph-set
134 render-composite-glyphs
135 render-add-glyph
136 render-add-glyph-from-picture
137 render-free-glyphs))
138
139 (pushnew :clx-ext-render *features*)
140
141 (define-extension "RENDER")
142
143 ;;;; Request constants
144
145 ;; Note: Although version numbers are given render.h where the request
146 ;; numbers are defined, render-query-version returns 0.0 all displays
147 ;; i tested. --GB 2004-07-21
148
149 (defconstant +X-RenderQueryVersion+ 0) ;done
150 (defconstant +X-RenderQueryPictFormats+ 1)
151 (defconstant +X-RenderQueryPictIndexValues+ 2) ;0.7
152 (defconstant +X-RenderQueryDithers+ 3)
153 (defconstant +X-RenderCreatePicture+ 4) ;done
154 (defconstant +X-RenderChangePicture+ 5) ;done
155 (defconstant +X-RenderSetPictureClipRectangles+ 6) ;done
156 (defconstant +X-RenderFreePicture+ 7) ;done
157 (defconstant +X-RenderComposite+ 8) ;we need better arglist
158 (defconstant +X-RenderScale+ 9)
159 (defconstant +X-RenderTrapezoids+ 10) ;low-level done
160 (defconstant +X-RenderTriangles+ 11) ;low-level done
161 (defconstant +X-RenderTriStrip+ 12)
162 (defconstant +X-RenderTriFan+ 13)
163 (defconstant +X-RenderColorTrapezoids+ 14) ;nyi in X server, not mentioned in renderproto.h
164 (defconstant +X-RenderColorTriangles+ 15) ;nyi in X server, not mentioned in renderproto.h
165 (defconstant +X-RenderTransform+ 16) ;commented out in render.h
166 (defconstant +X-RenderCreateGlyphSet+ 17) ;done
167 (defconstant +X-RenderReferenceGlyphSet+ 18) ;done
168 (defconstant +X-RenderFreeGlyphSet+ 19) ;done
169 (defconstant +X-RenderAddGlyphs+ 20) ;done, untested
170 (defconstant +X-RenderAddGlyphsFromPicture+ 21) ;done, untested
171 (defconstant +X-RenderFreeGlyphs+ 22) ;done, untested
172 (defconstant +X-RenderCompositeGlyphs8+ 23) ;done
173 (defconstant +X-RenderCompositeGlyphs16+ 24) ;done
174 (defconstant +X-RenderCompositeGlyphs32+ 25) ;done
175
176 ;; >= 0.1
177
178 (defconstant +X-RenderFillRectangles+ 26) ;single rectangle version done
179
180 ;; >= 0.5
181
182 (defconstant +X-RenderCreateCursor+ 27)
183
184 ;; >= 0.6
185
186 (defconstant +X-RenderSetPictureTransform+ 28) ;I don't understand what this one should do.
187 (defconstant +X-RenderQueryFilters+ 29) ;seems to be there on server side
188 ; some guts of its implementation there.
189 (defconstant +X-RenderSetPictureFilter+ 30)
190 (defconstant +X-RenderCreateAnimCursor+ 31) ;What has render to do with cursors?
191
192 ;;;;
193
194 ;; Sanity measures:
195
196 ;; We do away with the distinction between pict-format and
197 ;; picture-format-info. That is we cache picture-format-infos.
198
199 (defstruct render-info
200 major-version
201 minor-version
202 picture-formats)
203
204 (defun display-render-info (display)
205 (getf (xlib:display-plist display) 'render-info))
206
207 (defun (setf display-render-info) (new-value display)
208 (setf (getf (xlib:display-plist display) 'render-info)
209 new-value))
210
211 (defun ensure-render-initialized (display)
212 "Ensures that the RENDER extension is initialized. Should be called
213 by every function, which attempts to generate RENDER requests."
214 ;; xxx locking?
215 (unless (display-render-info display)
216 (let ((q (make-render-info)))
217 (multiple-value-bind (maj min) (render-query-version display)
218 (setf (render-info-major-version q) maj
219 (render-info-minor-version q) min)
220 (setf (render-info-picture-formats q)
221 (make-hash-table :test #'eql))
222 (dolist (pf (render-query-picture-formats display))
223 (setf (gethash (picture-format-id pf) (render-info-picture-formats q))
224 pf))
225 (setf (display-render-info display) q)))))
226
227 (defun find-matching-picture-formats
228 (display
229 &key depth-min depth-max depth
230 red-min red-max red
231 green-min green-max green
232 blue-min blue-max blue
233 alpha-min alpha-max alpha
234 type
235 colormap)
236 ;;
237 (ensure-render-initialized display)
238 (let ((res nil))
239 (maphash (lambda (k f)
240 (declare (ignore k))
241 (when (and
242 (or (null type) (eql (picture-format-type f) type))
243 (or (null colormap) (eql (picture-format-colormap f) colormap))
244 ;; min
245 (or (null depth-min) (>= (picture-format-depth f) depth-min))
246 (or (null red-min) (>= (byte-size (picture-format-red-byte f)) red-min))
247 (or (null green-min) (>= (byte-size (picture-format-green-byte f)) green-min))
248 (or (null blue-min) (>= (byte-size (picture-format-blue-byte f)) blue-min))
249 (or (null alpha-min) (>= (byte-size (picture-format-alpha-byte f)) alpha-min))
250 ;; max
251 (or (null depth-max) (<= (picture-format-depth f) depth-max))
252 (or (null red-max) (<= (byte-size (picture-format-red-byte f)) red-max))
253 (or (null green-max) (<= (byte-size (picture-format-green-byte f)) green-max))
254 (or (null blue-max) (<= (byte-size (picture-format-blue-byte f)) blue-max))
255 (or (null alpha-max) (<= (byte-size (picture-format-alpha-byte f)) alpha-max))
256 ;; match
257 (or (null depth) (= (picture-format-depth f) depth))
258 (or (null red) (= (byte-size (picture-format-red-byte f)) red))
259 (or (null green) (= (byte-size (picture-format-green-byte f)) green))
260 (or (null blue) (= (byte-size (picture-format-blue-byte f)) blue))
261 (or (null alpha) (= (byte-size (picture-format-alpha-byte f)) alpha)))
262 (pushnew f res)))
263 (render-info-picture-formats
264 (display-render-info display)))
265 res))
266
267 (defun find-window-picture-format (window)
268 "Find the picture format which matches the given window."
269 (let* ((vi (window-visual-info window))
270 (display (window-display window)))
271 (ensure-render-initialized display)
272 (case (visual-info-class vi)
273 ((:true-color)
274 (maphash (lambda (k f)
275 (declare (ignore k))
276 (when (and (eql (picture-format-type f) :direct)
277 (eql (picture-format-depth f) (drawable-depth window))
278 (eql (dpb -1 (picture-format-red-byte f) 0)
279 (visual-info-red-mask vi))
280 (eql (dpb -1 (picture-format-green-byte f) 0)
281 (visual-info-green-mask vi))
282 (eql (dpb -1 (picture-format-blue-byte f) 0)
283 (visual-info-blue-mask vi))
284 (eql (byte-size (picture-format-alpha-byte f)) 0))
285 (return-from find-window-picture-format f)))
286 (render-info-picture-formats
287 (display-render-info display))))
288 (t
289 ))))
290
291 (eval-when (:compile-toplevel :load-toplevel :execute)
292 (define-accessor picture (32)
293 ((index) index :blip)
294 ((index thing) `(resource-id-put ,index (picture-id ,thing))))
295 (define-accessor glyph-set (32)
296 ((index) index :blip)
297 ((index thing) `(resource-id-put ,index (glyph-set-id ,thing)))))
298
299 ;;; picture format
300
301 (defstruct picture-format
302 display
303 (id 0 :type (unsigned-byte 29))
304 type
305 depth
306 red-byte
307 green-byte
308 blue-byte
309 alpha-byte
310 colormap)
311
312 (defmethod print-object ((object picture-format) stream)
313 (let ((abbrev
314 (with-output-to-string (bag)
315 ;; build an abbreviated representation of the format
316 (let ((bytes (sort (list (cons "r" (picture-format-red-byte object))
317 (cons "g" (picture-format-green-byte object))
318 (cons "b" (picture-format-blue-byte object))
319 (cons "a" (picture-format-alpha-byte object)))
320 #'>
321 :key #'(lambda (x) (byte-position (cdr x))))))
322 (dolist (k bytes)
323 (unless (zerop (byte-size (cdr k)))
324 (format bag " ~A~D" (car k) (byte-size (cdr k)))))))))
325 (print-unreadable-object (object stream :type t :identity nil)
326 (format stream "~D ~S ~S ~S~A"
327 (picture-format-id object)
328 (picture-format-colormap object)
329 (picture-format-depth object)
330 (picture-format-type object) abbrev))))
331
332 (eval-when (:compile-toplevel :load-toplevel :execute)
333 (define-accessor picture-format (32)
334 ((index) `(gethash (read-card32 ,index)
335 (render-info-picture-formats (display-render-info .display.))))
336 ((index thing) `(write-card32 ,index (picture-format-id ,thing))))
337 (define-accessor render-op (8)
338 ((index) `(member8-get ,index
339 :clear :src :dst :over :over-reverse :in :in-reverse
340 :out :out-reverse :atop :atop-reverse :xor :add :saturate
341 '#:undefined-pict-op-Eh '#:undefined-pict-op-Fh
342 :disjoint-clear :disjoint-src :disjoint-dst :disjoint-over
343 :disjoint-over-reverse :disjoint-in :disjoint-in-reverse
344 :disjoint-out :disjoint-out-reverse :disjoint-atop
345 :disjoint-atop-reverse :disjoint-xor
346 '#:undefined-pict-op-1Ch '#:undefined-pict-op-1Dh
347 '#:undefined-pict-op-1Eh '#:undefined-pict-op-1Fh
348 :conjoint-clear :conjoint-src :conjoint-dst :conjoint-over
349 :conjoint-over-reverse :conjoint-in :conjoint-in-reverse
350 :conjoint-out :conjoint-out-reverse :conjoint-atop
351 :conjoint-atop-reverse :conjoint-xor))
352 ((index thing) `(member8-put ,index ,thing
353 :clear :src :dst :over :over-reverse :in :in-reverse
354 :out :out-reverse :atop :atop-reverse :xor :add :saturate
355 '#:undefined-pict-op-Eh '#:undefined-pict-op-Fh
356 :disjoint-clear :disjoint-src :disjoint-dst :disjoint-over
357 :disjoint-over-reverse :disjoint-in :disjoint-in-reverse
358 :disjoint-out :disjoint-out-reverse :disjoint-atop
359 :disjoint-atop-reverse :disjoint-xor
360 '#:undefined-pict-op-1Ch '#:undefined-pict-op-1Dh
361 '#:undefined-pict-op-1Eh '#:undefined-pict-op-1Fh
362 :conjoint-clear :conjoint-src :conjoint-dst :conjoint-over
363 :conjoint-over-reverse :conjoint-in :conjoint-in-reverse
364 :conjoint-out :conjoint-out-reverse :conjoint-atop
365 :conjoint-atop-reverse :conjoint-xor)))
366 (deftype render-op ()
367 '(member :clear :src :dst :over :over-reverse :in :in-reverse
368 :out :out-reverse :atop :atop-reverse :xor :add :saturate
369 :disjoint-clear :disjoint-src :disjoint-dst :disjoint-over
370 :disjoint-over-reverse :disjoint-in :disjoint-in-reverse
371 :disjoint-out :disjoint-out-reverse :disjoint-atop
372 :disjoint-atop-reverse :disjoint-xor
373 :conjoint-clear :conjoint-src :conjoint-dst :conjoint-over
374 :conjoint-over-reverse :conjoint-in :conjoint-in-reverse
375 :conjoint-out :conjoint-out-reverse :conjoint-atop
376 :conjoint-atop-reverse :conjoint-xor)))
377
378 ;; Now these pictures objects are like graphics contexts. I was about
379 ;; to introduce a synchronous mode, realizing that the RENDER protocol
380 ;; provides no provision to actually query a picture object's values.
381 ;; *sigh*
382
383 (def-clx-class (picture (:copier nil))
384 (id 0 :type resource-id)
385 (display nil :type (or null display))
386 (plist nil :type list) ; Extension hook
387 (format)
388 (%changed-p)
389 (%server-values)
390 (%values)
391 (%drawable))
392
393 (defun picture-drawable (picture)
394 (picture-%drawable picture))
395
396 ;; xx make id, display, format readonly
397
398 (defun %render-change-picture-clip-rectangles (picture rectangles)
399 "Dont call me, use (SETF PICTURE-CLIP-MASK) instead."
400 (declare (optimize (speed 0)))
401 (let ((display (picture-display picture)))
402 (ensure-render-initialized display)
403 (with-buffer-request (display (extension-opcode display "RENDER"))
404 (data +X-RenderSetPictureClipRectangles+)
405 (picture picture)
406 (int16 (picture-clip-x-origin picture))
407 (int16 (picture-clip-y-origin picture))
408 ((sequence :format int16) rectangles))))
409
410 (macrolet ((foo (&rest specs)
411 `(progn
412 ,@(loop for (type slot default) in specs
413 for index from 0
414 collect
415 `(progn
416 (defun ,(xintern 'picture- slot) (picture)
417 (aref (picture-%values picture) ,index))
418 (defun (setf ,(xintern 'picture- slot)) (new-value picture)
419 (setf (picture-%changed-p picture) t)
420 (setf (aref (picture-%values picture) ,index) new-value))))
421
422 (defun synchronise-picture-state (picture)
423 (when (picture-%changed-p picture)
424 (let ((display (picture-display picture)))
425 (ensure-render-initialized display)
426 (with-buffer-request (display (extension-opcode display "RENDER"))
427 (data +X-RenderChangePicture+)
428 (picture picture)
429 (mask
430 ,@(loop for (type slot default) in specs
431 for index from 0
432 collect
433 `(,type (and
434 ,(cond ((eql slot 'clip-mask)
435 `(not (typep (aref (picture-%values picture) ,index)
436 'sequence)))
437 (t
438 't))
439 (not (eq (aref (picture-%values picture) ,index)
440 (aref (picture-%server-values picture) ,index)))
441 (setf (aref (picture-%server-values picture) ,index)
442 (aref (picture-%values picture) ,index))))))))
443 ,(let ((index (position 'clip-mask specs :key #'second)))
444 `(unless (eql (aref (picture-%values picture) ,index)
445 (aref (picture-%server-values picture)
446 ,index))
447 (%render-change-picture-clip-rectangles
448 picture (aref (picture-%values picture) ,index))
449 (setf (aref (picture-%server-values picture) ,index)
450 (aref (picture-%values picture) ,index))))
451
452 (setf (picture-%changed-p picture) nil)))
453
454 (defun render-create-picture
455 (drawable
456 &key format
457 (picture (make-picture :display (drawable-display drawable)))
458 ,@(loop for (type slot default-value) in specs
459 collect (cond ((eql slot 'clip-mask)
460 `(clip-mask :none))
461 (t
462 slot)))
463 )
464 ;; xxx also offer to give a colormap instead of a picture-format
465 ;; values!
466 (let ((display (drawable-display drawable)))
467 (ensure-render-initialized display)
468 (unless format
469 ;; xxx check for drawable being a window
470 (setf format (find-window-picture-format drawable)))
471 (let ((pid (allocate-resource-id display picture 'picture)))
472 (setf (picture-id picture) pid)
473 (with-buffer-request (display (extension-opcode display "RENDER"))
474 (data +X-RenderCreatePicture+)
475 (resource-id pid)
476 (drawable drawable)
477 (picture-format format)
478 (mask
479 ,@(loop for (type slot default) in specs
480 collect
481 (cond ((eql slot 'clip-mask)
482 (list type `(and
483 (not (typep clip-mask 'sequence))
484 clip-mask)))
485 (t
486 (list type slot)))))))
487 (when (typep clip-mask 'sequence)
488 (%render-change-picture-clip-rectangles picture clip-mask))
489 (setf (picture-format picture) format)
490 (setf (picture-%server-values picture)
491 (vector ,@(loop for (type slot default) in specs
492 collect
493 `(or ,slot ,default))))
494 (setf (picture-%values picture) (copy-seq (picture-%server-values picture)))
495 (setf (picture-%drawable picture) drawable)
496 picture))
497
498 (defconstant +picture-state-length+
499 ,(length specs)) )))
500
501 (foo ((member :off :on) repeat :off)
502 ((or (member :none) picture) alpha-map :none)
503 (int16 alpha-x-origin 0)
504 (int16 alpha-y-origin 0)
505 (int16 clip-x-origin 0)
506 (int16 clip-y-origin 0)
507 ;; ### Now that is not correct is it?:
508 ((or (member :none) pixmap) clip-mask :none)
509 ((member :off :on) graphics-exposures :on)
510 ((member :clip-by-children :include-inferiors) subwindow-mode :clip-by-children)
511 ((member :sharp :smooth) poly-edge :smooth)
512 ((member :precise :imprecise) poly-mode :precise)
513 ((or (member :none) #||xatom||#) dither :none)
514 ((member :off :on) component-alpha :off)))
515
516 (defun render-free-picture (picture)
517 (let ((display (picture-display picture)))
518 (with-buffer-request (display (extension-opcode display "RENDER"))
519 (data +X-RenderFreePicture+)
520 (picture picture))))
521
522 (defun render-free-glyph-set (glyph-set)
523 (let ((display (glyph-set-display glyph-set)))
524 (with-buffer-request (display (extension-opcode display "RENDER"))
525 (data +X-RenderFreeGlyphSet+)
526 (glyph-set glyph-set))))
527
528 (defun render-query-version (display)
529 (with-buffer-request-and-reply (display (extension-opcode display "RENDER") nil)
530 ((data +X-RenderQueryVersion+)
531 (card32 0)
532 (card32 1))
533 (values
534 (card32-get 8)
535 (card32-get 12) )))
536
537 (defun render-query-picture-formats (display)
538 (with-buffer-request-and-reply (display (extension-opcode display "RENDER") nil)
539 ((data +X-RenderQueryPictFormats+))
540 (let ((n-picture-formats (card32-get 8))
541 (n-screens (card32-get 12))
542 (n-depths (card32-get 16))
543 (n-visuals (card32-get 20))
544 (n-subpixel (card32-get 24)))
545 (declare (ignore n-screens n-depths n-visuals n-subpixel))
546 (loop for i below n-picture-formats
547 collect
548 (let ((off (+ (* 8 4)
549 (* i 28)))) ;size of picture-format-info
550 (make-picture-format
551 :display display
552 :id (card32-get (+ off 0))
553 :type (member8-get (+ off 4) :indexed :direct)
554 :depth (card8-get (+ off 5))
555 :red-byte (byte (integer-length (card16-get (+ off 10)))
556 (card16-get (+ off 8)))
557 :green-byte (byte (integer-length (card16-get (+ off 14)))
558 (card16-get (+ off 12)))
559 :blue-byte (byte (integer-length (card16-get (+ off 18)))
560 (card16-get (+ off 16)))
561 :alpha-byte (byte (integer-length (card16-get (+ off 22)))
562 (card16-get (+ off 20)))
563 :colormap (let ((cmid (card32-get (+ off 24))))
564 (unless (zerop cmid)
565 (lookup-colormap display cmid)))))))))
566
567 (defun render-fill-rectangle (picture op color x1 y1 w h)
568 (let ((display (picture-display picture)))
569 (ensure-render-initialized display)
570 (synchronise-picture-state picture)
571 (with-buffer-request (display (extension-opcode display "RENDER"))
572 (data +X-RenderFillRectangles+)
573 (render-op op) ;op
574 (card8 0) ;pad
575 (card16 0) ;pad
576 (resource-id (picture-id picture))
577 (card16 (elt color 0)) (card16 (elt color 1)) (card16 (elt color 2)) (card16 (elt color 3))
578 (int16 x1) (int16 y1) (card16 w) (card16 h))))
579
580 ;; fill rectangles, colors.
581
582 (defun render-triangles-1 (picture op source src-x src-y format coord-sequence)
583 ;; For performance reasons we do a special typecase on (simple-array
584 ;; (unsigned-byte 32) (*)), so that it'll be possible to have high
585 ;; performance rasters.
586 (macrolet ((guts ()
587 '(let ((display (picture-display picture)))
588 (synchronise-picture-state picture)
589 (synchronise-picture-state source)
590 (with-buffer-request (display (extension-opcode display "RENDER"))
591 (data +X-RenderTriangles+)
592 (render-op op) ;op
593 (card8 0) ;pad
594 (card16 0) ;pad
595 (resource-id (picture-id source))
596 (resource-id (picture-id picture))
597 (picture-format format)
598 (int16 src-x)
599 (int16 src-y)
600 ((sequence :format int32) coord-sequence) ))))
601 (typecase coord-sequence
602 ((simple-array (unsigned-byte 32) (*))
603 (locally
604 (declare (type (simple-array (unsigned-byte 32) (*)) coord-sequence))
605 (guts)))
606 (t
607 (guts)))))
608
609 #||
610 (defun render-set-picture-transform (picture mxx mxy dx mxy myy dy &optional (mwx 0) (mwy 0) (dw 1))
611 ...)
612 ||#
613
614 (defun render-set-picture-transform (picture a b c d e f p q r)
615 (let ((display (picture-display picture)))
616 (ensure-render-initialized display)
617 (synchronise-picture-state picture)
618 (with-buffer-request (display (extension-opcode display "RENDER"))
619 (data +X-RenderSetPictureTransform+)
620 #|
621 (card8 0) ;; render-op op) ;op
622 (card8 0) ;pad
623 (card16 0) ;pad
624 |#
625 (resource-id (picture-id picture))
626
627 (card32 a)
628 (card32 b)
629 (card32 c)
630
631 (card32 d)
632 (card32 e)
633 (card32 f)
634
635 (card32 p)
636 (card32 q)
637 (card32 r))))
638
639 (defun render-query-filters (drawable)
640 (let ((display (drawable-display drawable)))
641 (with-buffer-request-and-reply (display (extension-opcode display "RENDER") nil)
642 ((data +X-RenderQueryFilters+)
643 (drawable drawable))
644 (let* ((len (card32-get 4))
645 (n-aliases (card32-get 8))
646 (n-filters (card32-get 12))
647 (off (+ (* 8 4) (* 4 (ceiling (* 2 n-aliases) 4)))))
648 (print (list :aliases
649 (loop for i below n-aliases collect (card16-get (+ (* 8 4) (* i 2))))))
650 (print (list :foo len n-aliases n-filters
651 (loop for i below len
652 collect (card8-get (+ off 0 (* 4 i)))
653 collect (card8-get (+ off 1 (* 4 i)))
654 collect (card8-get (+ off 2 (* 4 i)))
655 collect (card8-get (+ off 3 (* 4 i))))))
656 (print
657 (labels ((grab-string (j)
658 (let ((n (card8-get j)))
659 (incf j)
660 (values
661 (map 'string #'code-char (loop repeat n collect (card8-get j) do (incf j)))
662 j))))
663 (loop repeat n-filters collect
664 (multiple-value-bind (s j) (grab-string off)
665 (setf off j)
666 (intern (string-upcase s) :keyword)))))
667 #+NIL
668 (loop for i below n-picture-formats
669 collect
670 (let ((off (+ (* 8 4)
671 (* i 28)))) ;size of picture-format-info
672 (make-picture-format
673 :display display
674 :id (card32-get (+ off 0))
675 :type (member8-get (+ off 4) :indexed :direct)
676 :depth (card8-get (+ off 5))
677 :red-byte (byte (integer-length (card16-get (+ off 10)))
678 (card16-get (+ off 8)))
679 :green-byte (byte (integer-length (card16-get (+ off 14)))
680 (card16-get (+ off 12)))
681 :blue-byte (byte (integer-length (card16-get (+ off 18)))
682 (card16-get (+ off 16)))
683 :alpha-byte (byte (integer-length (card16-get (+ off 22)))
684 (card16-get (+ off 20)))
685 :colormap (let ((cmid (card32-get (+ off 24))))
686 (unless (zerop cmid)
687 (lookup-colormap display cmid))))))))))
688
689 (defun render-set-filter (picture filter)
690 (let ((display (picture-display picture)))
691 (ensure-render-initialized display)
692 (synchronise-picture-state picture)
693 (with-buffer-request (display (extension-opcode display "RENDER"))
694 (data +X-RenderSetPictureFilter+)
695 (resource-id (picture-id picture))
696 (card16 (length filter))
697 (card16 0) ;pad
698 ((sequence :format card8) (map 'vector #'char-code filter)))))
699
700
701
702 #||
703 (defun render-triangle (destination source x1 y1 x2 y2 x3 y3 &key (src-x 0) (src-y 0) (format nil) (op :over))
704 (render-triangles-1 destination op source ...)
705 )
706 ||#
707
708 (defun render-trapezoids-1 (picture op source src-x src-y mask-format coord-sequence)
709 ;; coord-sequence is top bottom
710 ;; line-1-x1 line-1-y1 line-1-x2 line-1-y2
711 ;; line-2-x1 line-2-y1 line-2-x2 line-2-y2 ...
712 ;;
713 (let ((display (picture-display picture)))
714 (synchronise-picture-state picture)
715 (synchronise-picture-state source)
716 (with-buffer-request (display (extension-opcode display "RENDER"))
717 (data +X-RenderTrapezoids+)
718 (render-op op) ;op
719 (card8 0) ;pad
720 (card16 0) ;pad
721 (resource-id (picture-id source))
722 (resource-id (picture-id picture))
723 ((or (member :none) picture-format) mask-format)
724 (int16 src-x)
725 (int16 src-y)
726 ((sequence :format int32) coord-sequence) )))
727
728 (defun render-composite (op
729 source mask dest
730 src-x src-y mask-x mask-y dst-x dst-y
731 width height)
732 (let ((display (picture-display source)))
733 (synchronise-picture-state source)
734 (when mask (synchronise-picture-state mask))
735 (synchronise-picture-state dest)
736 (with-buffer-request (display (extension-opcode display "RENDER"))
737 (data +X-RenderComposite+)
738 (render-op op) ;op
739 (card8 0) ;pad
740 (card16 0) ;pad
741 (resource-id (picture-id source))
742 (resource-id (if mask (picture-id mask) 0))
743 (resource-id (picture-id dest))
744 (int16 src-x)
745 (int16 src-y)
746 (int16 mask-x)
747 (int16 mask-y)
748 (int16 dst-x)
749 (int16 dst-y)
750 (card16 width)
751 (card16 height))))
752
753 (def-clx-class (glyph-set (:copier nil)
754 )
755 (id 0 :type resource-id)
756 (display nil :type (or null display))
757 (plist nil :type list) ; Extension hook
758 (format))
759
760 (defun render-create-glyph-set (format &key glyph-set)
761 (let ((display (picture-format-display format)))
762 (let* ((glyph-set (or glyph-set (make-glyph-set :display display)))
763 (gsid (setf (glyph-set-id glyph-set)
764 (allocate-resource-id display glyph-set 'glyph-set))))
765 (declare (ignore gsid))
766 (setf (glyph-set-format glyph-set) format)
767 (with-buffer-request (display (extension-opcode display "RENDER"))
768 (data +X-RenderCreateGlyphSet+)
769 (glyph-set glyph-set)
770 (picture-format format))
771 glyph-set)))
772
773 (defun render-reference-glyph-set (existing-glyph-set &key glyph-set)
774 (let ((display (glyph-set-display existing-glyph-set)))
775 (let* ((glyph-set (or glyph-set (make-glyph-set :display display)))
776 (gsid (setf (glyph-set-id glyph-set)
777 (allocate-resource-id display glyph-set 'glyph-set))))
778 (declare (ignore gsid))
779 (setf (glyph-set-format glyph-set)
780 (glyph-set-format existing-glyph-set))
781 (with-buffer-request (display (extension-opcode display "RENDER"))
782 (data +X-RenderReferenceGlyphSet+)
783 (glyph-set glyph-set)
784 (glyph-set existing-glyph-set))
785 glyph-set)))
786
787 (defun render-composite-glyphs-8 (dest glyph-set source dest-x dest-y sequence
788 &key (op :over)
789 (alu op) ;for the fun of it
790 (src-x 0)
791 (src-y 0)
792 (mask-format :none)
793 (start 0)
794 (end (length sequence)))
795 (let ((display (picture-display dest)))
796 (ensure-render-initialized display)
797 (synchronise-picture-state dest)
798 (synchronise-picture-state source)
799 (when (stringp sequence)
800 ;; lazy me, but then you should not confuse glyphs with
801 ;; characters anyway.
802 (setf sequence (map 'vector #'char-code sequence)))
803 (with-buffer-request (display (extension-opcode display "RENDER"))
804 (data +X-RenderCompositeGlyphs8+)
805 (render-op alu)
806 (card8 0) (card16 0) ;padding
807 (picture source)
808 (picture dest)
809 ((or (member :none) picture-format) mask-format)
810 (glyph-set glyph-set)
811 (int16 src-x) (int16 src-y)
812 (card8 (- end start)) ;length of glyph elt
813 (card8 0) (card16 0) ;padding
814 (int16 dest-x) (int16 dest-y) ;dx, dy
815 ((sequence :format card8) sequence))))
816
817 (defmacro %render-composite-glyphs
818 (opcode type transform display dest glyph-set source dest-x dest-y sequence
819 alu src-x src-y mask-format start end)
820 (let ((size (ecase type (card8 1) (card16 2) (card32 4)))
821 ;; FIXME: the last chunk for CARD8 can be 254.
822 (chunksize (ecase type (card8 252) (card16 254) (card32 254))))
823 `(multiple-value-bind (nchunks leftover)
824 (floor (- end start) ,chunksize)
825 (let* ((payloadsize (+ (* nchunks (+ 8 (* ,chunksize ,size)))
826 (if (> leftover 0)
827 (+ 8 (* 4 (ceiling (* leftover ,size) 4)))
828 0)))
829 (request-length (+ 7 (/ payloadsize 4))))
830 (declare (integer request-length))
831 (with-buffer-request (,display (extension-opcode ,display "RENDER") :length (* 4 request-length))
832 (data ,opcode)
833 (length request-length)
834 (render-op ,alu)
835 (card8 0) (card16 0) ;padding
836 (picture ,source)
837 (picture ,dest)
838 ((or (member :none) picture-format) ,mask-format)
839 (glyph-set ,glyph-set)
840 (int16 ,src-x) (int16 ,src-y)
841 (progn
842 (let ((boffset (+ buffer-boffset 28))
843 (start ,start)
844 (end ,end)
845 (dest-x ,dest-x)
846 (dest-y ,dest-y))
847 (dotimes (i nchunks)
848 (set-buffer-offset boffset)
849 (put-items (0)
850 (card8 ,chunksize)
851 (card8 0)
852 (card16 0)
853 (int16 dest-x)
854 (int16 dest-y)
855 ((sequence :start start :end (+ start ,chunksize) :format ,type :transform ,transform :appending t) ,sequence))
856 (setq dest-x 0 dest-y 0)
857 (incf boffset (+ 8 (* ,chunksize ,size)))
858 (incf start ,chunksize))
859 (when (> leftover 0)
860 (set-buffer-offset boffset)
861 (put-items (0)
862 (card8 leftover)
863 (card8 0)
864 (card16 0)
865 (int16 dest-x)
866 (int16 dest-y)
867 ((sequence :start start :end end :format ,type :transform ,transform :appending t) ,sequence))
868 ;; padding?
869 (incf boffset (+ 8 (* 4 (ceiling (* leftover ,size) 4)))))
870 (setf (buffer-boffset ,display) boffset))))))))
871
872 (defun render-composite-glyphs (dest glyph-set source dest-x dest-y sequence
873 &key (op :over)
874 (alu op) ;for the fun of it
875 (src-x 0)
876 (src-y 0)
877 (mask-format :none)
878 (start 0)
879 (end (length sequence)))
880 ;; xxx do we want to go with some translate function as draw-glyphs?
881 (declare (type array-index start end))
882 (let ((display (picture-display dest)))
883 (ensure-render-initialized display)
884 (synchronise-picture-state dest)
885 (synchronise-picture-state source)
886 ;; hmm find out the element size
887 (typecase sequence
888 ((array (unsigned-byte 8) (*))
889 (%render-composite-glyphs +X-RenderCompositeGlyphs8+ card8 nil
890 display dest glyph-set source dest-x dest-y sequence alu src-x
891 src-y mask-format start end))
892 ((array (unsigned-byte 16) (*))
893 (%render-composite-glyphs +X-RenderCompositeGlyphs16+ card16 nil
894 display dest glyph-set source dest-x dest-y sequence alu src-x
895 src-y mask-format start end))
896 ((array (unsigned-byte 32) (*))
897 (%render-composite-glyphs +X-RenderCompositeGlyphs32+ card32 nil
898 display dest glyph-set source dest-x dest-y sequence alu src-x
899 src-y mask-format start end))
900 (string
901 (%render-composite-glyphs #.(cond ((<= char-code-limit (expt 2 8)) '+X-RenderCompositeGlyphs8+)
902 ((<= char-code-limit (expt 2 16)) '+X-RenderCompositeGlyphs16+)
903 ((<= char-code-limit (expt 2 32)) '+X-RenderCompositeGlyphs32+)
904 (t
905 (error "Wow!")))
906 #.(cond ((<= char-code-limit (expt 2 8)) 'card8)
907 ((<= char-code-limit (expt 2 16)) 'card16)
908 ((<= char-code-limit (expt 2 32)) 'card32)
909 (t
910 (error "Wow!")))
911 #'char-code
912 display dest glyph-set source dest-x dest-y sequence alu src-x
913 src-y mask-format start end))
914 (t
915 ;; should we bother testing the array element type?
916 (%render-composite-glyphs +X-RenderCompositeGlyphs32+ card32
917 #'(lambda (elt)
918 (if (characterp elt)
919 (char-code elt)
920 elt))
921 display dest glyph-set source dest-x dest-y sequence alu src-x
922 src-y mask-format start end))) ))
923
924 ;; --- idea: Allow data to be an image to avoid unecessary consing? - noss
925 (defun render-add-glyph (glyph-set id &key x-origin y-origin x-advance y-advance data)
926 (let ((display (glyph-set-display glyph-set)))
927 (ensure-render-initialized display)
928 (let* ((w (array-dimension data 1))
929 (h (array-dimension data 0))
930 (bitmap-format (display-bitmap-format display))
931 (unit (bitmap-format-unit bitmap-format))
932 (byte-lsb-first-p (display-image-lsb-first-p display))
933 (bit-lsb-first-p (bitmap-format-lsb-first-p bitmap-format)))
934 (let* ((byte-per-line (* 4 (ceiling
935 (* w (picture-format-depth (glyph-set-format glyph-set)))
936 32)))
937 (request-length (+ 28
938 (* h byte-per-line))))
939 (with-buffer-request (display (extension-opcode display "RENDER"))
940 (data +X-RenderAddGlyphs+)
941 (length (ceiling request-length 4))
942 (glyph-set glyph-set)
943 (card32 1) ;number glyphs
944 (card32 id) ;id
945 (card16 w)
946 (card16 h)
947 (int16 x-origin)
948 (int16 y-origin)
949 (int16 x-advance)
950 (int16 y-advance)
951 (progn
952 (setf (buffer-boffset display) (advance-buffer-offset 28))
953 (let ((im (create-image :width w :height h :depth 8 :data data)))
954 (write-image-z display im 0 0 w h
955 byte-per-line ;padded bytes per line
956 unit byte-lsb-first-p bit-lsb-first-p)) ))) )))
957
958 (defun render-add-glyph-from-picture (glyph-set picture
959 &key x-origin y-origin x-advance y-advance
960 x y width height)
961 ;; untested, the duplication of x-origin seems bogus.
962 ;; Still untested, but these modifications seem to be more likely, (x,y) would be the offset into the picture.
963 ;; and orgin advance would be properties of the defined glyph.
964 (let ((display (glyph-set-display glyph-set)))
965 (with-buffer-request (display (extension-opcode display "RENDER"))
966 (data +X-RenderAddGlyphsFromPicture+)
967 (glyph-set glyph-set)
968 (picture picture)
969 (card16 width)
970 (card16 height)
971 (card16 x-origin)
972 (card16 y-origin)
973 (card16 x-advance)
974 (card16 y-advance)
975 (card16 x)
976 (card16 y))))
977
978 ;; untested
979 (defun render-free-glyphs (glyph-set glyphs)
980 "This request removes glyphs from glyph-set. Each glyph must exist in glyph-set (else a Match error results)."
981 (let ((display (glyph-set-display glyph-set)))
982 (with-buffer-request (display (extension-opcode display "RENDER"))
983 (data +X-RenderFreeGlyphs+)
984 (glyph-set glyph-set)
985 ((sequence :format card32) glyphs))))
986
987
988 #||
989 ;;; --------------------------------------------------------------------------------
990
991 ;; testing code:
992
993 (defun x (op)
994 (let ((dpy (open-display "")))
995 (render-query-version dpy)
996 (unwind-protect
997 (let* ((win (screen-root (first (display-roots dpy))))
998 (display dpy)
999 (pf (find-window-picture-format win))
1000 (pm (xlib:create-pixmap
1001 :depth (xlib:drawable-depth win)
1002 :drawable win :width 1 :height 1))
1003 (pm.p (render-create-picture pm
1004 :format pf
1005 :repeat :on))
1006 (win.p (render-create-picture win :format pf))
1007 (gs (render-create-glyph-set (first
1008 (find-matching-picture-formats
1009 dpy
1010 :alpha 8
1011 :red-max 0
1012 :green-max 0
1013 :blue-max 0)))))
1014 (xlib:clear-area win)
1015 (render-fill-rectangle pm.p :src (list #xFFFF 0 0 0) 0 0 100 100)
1016 (render-add-glyph gs 18
1017 :data (make-array (list 3 3)
1018 :initial-contents '((255 000 000)
1019 (000 255 000)
1020 (000 000 255))
1021 :element-type '(unsigned-byte 8))
1022 :x-advance 4
1023 :y-advance 0
1024 :x-origin 0
1025 :y-origin 0)
1026 (let ((w 50)
1027 (h 50))
1028 (let ((data (make-array (list h w) :element-type '(unsigned-byte 8) :initial-element 0)))
1029 (dotimes (i w)
1030 (dotimes (j h)
1031 (setf (aref data i j) (* 3 i))))
1032 (render-add-glyph gs 17
1033 :data data
1034 :x-advance (+ w 2)
1035 :y-advance 0
1036 :x-origin 0
1037 :y-origin 0)))
1038
1039 (render-composite-glyphs-8 win.p gs pm.p
1040 200 330
1041 (vector 17 18 18 17 17 17 17 17 17 17)
1042 :alu op
1043 )
1044 ;;
1045 (display-finish-output dpy)
1046 (close-display dpy)))))
1047
1048 (defun z (op)
1049 (let ((dpy (open-display "")))
1050 (unwind-protect
1051 (let* ((win (screen-root (first (display-roots dpy))))
1052 (pic (render-create-picture win))
1053 (fmt (first (find-matching-picture-formats
1054 dpy
1055 :red-min 8
1056 :green-min 8
1057 :blue-min 8
1058 :alpha-min 8)))
1059 (px (xlib:create-pixmap :width 256 :height 256 :depth (picture-format-depth fmt)
1060 :drawable win))
1061 (px.pic (render-create-picture px :format fmt))
1062 (px.gc (xlib:create-gcontext :drawable px)))
1063 (xlib:clear-area win)
1064 ;;
1065 (render-fill-rectangle px.pic :src
1066 (list #x8000 #x0000 #x8000 #xFFFF)
1067 0 0 256 256)
1068
1069 (render-composite :src pic pic px.pic
1070 350 350 350 350 0 0 256 256)
1071 ;;
1072 (render-fill-rectangle px.pic :over
1073 (list #x8000 #x8000 #x8000 #x8000)
1074 0 0 100 100)
1075 (render-composite :src
1076 px.pic px.pic pic
1077 0 0 0 0 350 350
1078 256 256)
1079 (render-fill-rectangle pic op (list #x0 #x0 #x0 #x8000) 200 200 800 800)
1080 (display-finish-output dpy))
1081 (close-display dpy))))
1082
1083 ;;; ----------------------------------------------------------------------------------------------------
1084
1085 (defun y (op)
1086 (let ((dpy (open-display "")))
1087 (render-query-version dpy)
1088 (unwind-protect
1089 (let* ((win (screen-root (first (display-roots dpy))))
1090 (pic
1091 (render-create-picture win))
1092 (px (xlib:create-pixmap :drawable win
1093 :width 256
1094 :height 256
1095 :depth 32))
1096 (px.gc (xlib:create-gcontext :drawable px)))
1097 (dotimes (x 256)
1098 (dotimes (y 256)
1099 (setf (xlib:gcontext-foreground px.gc)
1100 (dpb x (byte 8 24)
1101 (dpb y (byte 8 16)
1102 (dpb y (byte 8 8)
1103 y))))
1104 (xlib:draw-point px px.gc x y)
1105 ))
1106 (xlib:clear-area win)
1107 (let ((q (render-create-picture px
1108 :format
1109 (first (find-matching-picture-formats
1110 dpy
1111 :depth 32
1112 :alpha 8 :red 8 :green 8 :blue 8))
1113 :component-alpha :on
1114 :repeat :off)))
1115 (render-composite op
1116 q
1117 q
1118 pic
1119 0 0
1120 0 0
1121 100 100
1122 400 400))
1123 (let ()
1124 ;;(render-fill-rectangle pic op (list 255 255 255 255) 100 100 200 200)
1125 (display-finish-output dpy)))
1126 (close-display dpy))))
1127
1128 (defun zz ()
1129 (let* ((dpy (xlib:open-display ""))
1130 (win (screen-root (first (display-roots dpy))))
1131 (pic (render-create-picture win)))
1132 (xlib:clear-area win)
1133 (setf (picture-clip-mask pic) (list 100 100 200 2000))
1134 (render-fill-rectangle pic :over (list #xFFFF 0 0 #x400) 0 0 2000 2000)
1135 (display-finish-output dpy)
1136 (close-display dpy)))
1137 ||#
1138
1139
1140 ;;;; Cursors
1141
1142 (defun render-create-cursor (picture &optional (x 0) (y 0))
1143 (let ((display (picture-display picture)))
1144 (ensure-render-initialized display)
1145 (synchronise-picture-state picture)
1146 (let* ((cursor (make-cursor :display display))
1147 (cid (allocate-resource-id display cursor 'cursor)))
1148 (setf (cursor-id cursor) cid)
1149 (with-buffer-request (display (extension-opcode display "RENDER"))
1150 (data +X-RenderCreateCursor+)
1151 (resource-id cid)
1152 (resource-id (picture-id picture))
1153 (card16 x)
1154 (card16 y))
1155 cursor)))

  ViewVC Help
Powered by ViewVC 1.1.5