fb.h revision 03b705cf
1/*
2 * Copyright © 1998 Keith Packard
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#ifndef FB_H
25#define FB_H
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <xorg-server.h>
32#include <servermd.h>
33#include <gcstruct.h>
34#include <colormap.h>
35#include <windowstr.h>
36#include <regionstr.h>
37
38#include <stdbool.h>
39#include <pixman.h>
40
41#if HAS_DEBUG_FULL
42#define DBG(x) ErrorF x
43#else
44#define DBG(x)
45#endif
46
47#include "sfb.h"
48
49#include "../../compat-api.h"
50
51#define WRITE(ptr, val) (*(ptr) = (val))
52#define READ(ptr) (*(ptr))
53
54/*
55 * This single define controls the basic size of data manipulated
56 * by this software; it must be log2(sizeof (FbBits) * 8)
57 */
58#define FB_SHIFT    LOG2_BITMAP_PAD
59
60#define FB_UNIT	    (1 << FB_SHIFT)
61#define FB_HALFUNIT (1 << (FB_SHIFT-1))
62#define FB_MASK	    (FB_UNIT - 1)
63#define FB_ALLONES  ((FbBits) -1)
64
65#if IMAGE_BYTE_ORDER != LSBFirst
66#error "IMAGE_BYTE_ORDER must be LSBFirst"
67#endif
68
69#if GLYPHPADBYTES != 4
70#error "GLYPHPADBYTES must be 4"
71#endif
72
73#if FB_SHIFT != 5
74#error "FB_SHIFT ala LOG2_BITMAP_PAD must be 5"
75#endif
76
77#define FB_STIP_SHIFT	LOG2_BITMAP_PAD
78#define FB_STIP_UNIT	(1 << FB_STIP_SHIFT)
79#define FB_STIP_MASK	(FB_STIP_UNIT - 1)
80#define FB_STIP_ALLONES	((FbStip) -1)
81#define FbFullMask(n)   ((n) == FB_UNIT ? FB_ALLONES : ((((FbBits) 1) << n) - 1))
82
83typedef uint32_t FbBits;
84typedef FbBits FbStip;
85typedef int FbStride;
86
87#include "fbrop.h"
88
89#define FbScrLeft(x,n)	((x) >> (n))
90#define FbScrRight(x,n)	((x) << (n))
91/* #define FbLeftBits(x,n)	((x) & ((((FbBits) 1) << (n)) - 1)) */
92#define FbLeftStipBits(x,n) ((x) & ((((FbStip) 1) << (n)) - 1))
93#define FbStipMoveLsb(x,s,n)	(FbStipRight (x,(s)-(n)))
94#define FbPatternOffsetBits	0
95
96#define FbStipLeft(x,n)	FbScrLeft(x,n)
97#define FbStipRight(x,n) FbScrRight(x,n)
98
99#define FbRotLeft(x,n)	FbScrLeft(x,n) | (n ? FbScrRight(x,FB_UNIT-n) : 0)
100#define FbRotRight(x,n)	FbScrRight(x,n) | (n ? FbScrLeft(x,FB_UNIT-n) : 0)
101
102#define FbRotStipLeft(x,n)  FbStipLeft(x,n) | (n ? FbStipRight(x,FB_STIP_UNIT-n) : 0)
103#define FbRotStipRight(x,n)  FbStipRight(x,n) | (n ? FbStipLeft(x,FB_STIP_UNIT-n) : 0)
104
105#define FbLeftMask(x)	    ( ((x) & FB_MASK) ? \
106			     FbScrRight(FB_ALLONES,(x) & FB_MASK) : 0)
107#define FbRightMask(x)	    ( ((FB_UNIT - (x)) & FB_MASK) ? \
108			     FbScrLeft(FB_ALLONES,(FB_UNIT - (x)) & FB_MASK) : 0)
109
110#define FbLeftStipMask(x)   ( ((x) & FB_STIP_MASK) ? \
111			     FbStipRight(FB_STIP_ALLONES,(x) & FB_STIP_MASK) : 0)
112#define FbRightStipMask(x)  ( ((FB_STIP_UNIT - (x)) & FB_STIP_MASK) ? \
113			     FbScrLeft(FB_STIP_ALLONES,(FB_STIP_UNIT - (x)) & FB_STIP_MASK) : 0)
114
115#define FbBitsMask(x,w)	(FbScrRight(FB_ALLONES,(x) & FB_MASK) & \
116			 FbScrLeft(FB_ALLONES,(FB_UNIT - ((x) + (w))) & FB_MASK))
117
118#define FbStipMask(x,w)	(FbStipRight(FB_STIP_ALLONES,(x) & FB_STIP_MASK) & \
119			 FbStipLeft(FB_STIP_ALLONES,(FB_STIP_UNIT - ((x)+(w))) & FB_STIP_MASK))
120
121#define FbMaskBits(x,w,l,n,r) { \
122    n = (w); \
123    r = FbRightMask((x)+n); \
124    l = FbLeftMask(x); \
125    if (l) { \
126	n -= FB_UNIT - ((x) & FB_MASK); \
127	if (n < 0) { \
128	    n = 0; \
129	    l &= r; \
130	    r = 0; \
131	} \
132    } \
133    n >>= FB_SHIFT; \
134}
135
136#define FbByteMaskInvalid   0x10
137
138#define FbPatternOffset(o,t)  ((o) ^ (FbPatternOffsetBits & ~(sizeof (t) - 1)))
139
140#define FbPtrOffset(p,o,t)		((t *) ((CARD8 *) (p) + (o)))
141#define FbSelectPatternPart(xor,o,t)	((xor) >> (FbPatternOffset (o,t) << 3))
142#define FbStorePart(dst,off,t,xor)	(WRITE(FbPtrOffset(dst,off,t), \
143					 FbSelectPart(xor,off,t)))
144#ifndef FbSelectPart
145#define FbSelectPart(x,o,t) FbSelectPatternPart(x,o,t)
146#endif
147
148#define FbMaskBitsBytes(x,w,copy,l,lb,n,r,rb) { \
149    n = (w); \
150    lb = 0; \
151    rb = 0; \
152    r = FbRightMask((x)+n); \
153    if (r) { \
154	/* compute right byte length */ \
155	if ((copy) && (((x) + n) & 7) == 0) { \
156	    rb = (((x) + n) & FB_MASK) >> 3; \
157	} else { \
158	    rb = FbByteMaskInvalid; \
159	} \
160    } \
161    l = FbLeftMask(x); \
162    if (l) { \
163	/* compute left byte length */ \
164	if ((copy) && ((x) & 7) == 0) { \
165	    lb = ((x) & FB_MASK) >> 3; \
166	} else { \
167	    lb = FbByteMaskInvalid; \
168	} \
169	/* subtract out the portion painted by leftMask */ \
170	n -= FB_UNIT - ((x) & FB_MASK); \
171	if (n < 0) { \
172	    if (lb != FbByteMaskInvalid) { \
173		if (rb == FbByteMaskInvalid) { \
174		    lb = FbByteMaskInvalid; \
175		} else if (rb) { \
176		    lb |= (rb - lb) << (FB_SHIFT - 3); \
177		    rb = 0; \
178		} \
179	    } \
180	    n = 0; \
181	    l &= r; \
182	    r = 0; \
183	}\
184    } \
185    n >>= FB_SHIFT; \
186}
187
188#define FbDoLeftMaskByteRRop(dst,lb,l,and,xor) { \
189    switch (lb) { \
190    case (sizeof (FbBits) - 3) | (1 << (FB_SHIFT - 3)): \
191	FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \
192	break; \
193    case (sizeof (FbBits) - 3) | (2 << (FB_SHIFT - 3)): \
194	FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \
195	FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \
196	break; \
197    case (sizeof (FbBits) - 2) | (1 << (FB_SHIFT - 3)): \
198	FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \
199	break; \
200    case sizeof (FbBits) - 3: \
201	FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \
202    case sizeof (FbBits) - 2: \
203	FbStorePart(dst,sizeof (FbBits) - 2,CARD16,xor); \
204	break; \
205    case sizeof (FbBits) - 1: \
206	FbStorePart(dst,sizeof (FbBits) - 1,CARD8,xor); \
207	break; \
208    default: \
209	WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, l)); \
210	break; \
211    } \
212}
213
214#define FbDoRightMaskByteRRop(dst,rb,r,and,xor) { \
215    switch (rb) { \
216    case 1: \
217	FbStorePart(dst,0,CARD8,xor); \
218	break; \
219    case 2: \
220	FbStorePart(dst,0,CARD16,xor); \
221	break; \
222    case 3: \
223	FbStorePart(dst,0,CARD16,xor); \
224	FbStorePart(dst,2,CARD8,xor); \
225	break; \
226    default: \
227	WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, r)); \
228    } \
229}
230
231#define FbMaskStip(x,w,l,n,r) { \
232    n = (w); \
233    r = FbRightStipMask((x)+n); \
234    l = FbLeftStipMask(x); \
235    if (l) { \
236	n -= FB_STIP_UNIT - ((x) & FB_STIP_MASK); \
237	if (n < 0) { \
238	    n = 0; \
239	    l &= r; \
240	    r = 0; \
241	} \
242    } \
243    n >>= FB_STIP_SHIFT; \
244}
245
246/*
247 * These macros are used to transparently stipple
248 * in copy mode; the expected usage is with 'n' constant
249 * so all of the conditional parts collapse into a minimal
250 * sequence of partial word writes
251 *
252 * 'n' is the bytemask of which bytes to store, 'a' is the address
253 * of the FbBits base unit, 'o' is the offset within that unit
254 *
255 * The term "lane" comes from the hardware term "byte-lane" which
256 */
257
258#define FbLaneCase1(n,a,o)						\
259    if ((n) == 0x01) {							\
260	WRITE((CARD8 *) ((a)+FbPatternOffset(o,CARD8)), fgxor);		\
261    }
262
263#define FbLaneCase2(n,a,o)						\
264    if ((n) == 0x03) {							\
265	WRITE((CARD16 *) ((a)+FbPatternOffset(o,CARD16)), fgxor);	\
266    } else {								\
267	FbLaneCase1((n)&1,a,o)						\
268	FbLaneCase1((n)>>1,a,(o)+1)					\
269    }
270
271#define FbLaneCase4(n,a,o)						\
272    if ((n) == 0x0f) {							\
273	WRITE((CARD32 *) ((a)+FbPatternOffset(o,CARD32)), fgxor);	\
274    } else {								\
275	FbLaneCase2((n)&3,a,o)						\
276	FbLaneCase2((n)>>2,a,(o)+2)					\
277    }
278
279#define FbLaneCase(n,a)   FbLaneCase4(n,(CARD8 *) (a),0)
280
281typedef struct {
282	long changes;
283	long serial;
284	GCFuncs *old_funcs;
285	void *priv;
286
287	FbBits and, xor;            /* reduced rop values */
288	FbBits bgand, bgxor;        /* for stipples */
289	FbBits fg, bg, pm;          /* expanded and filled */
290	unsigned int dashLength;    /* total of all dash elements */
291	unsigned char evenStipple;  /* stipple is even */
292	unsigned char bpp;          /* current drawable bpp */
293} FbGCPrivate, *FbGCPrivPtr;
294
295extern DevPrivateKeyRec sna_gc_key;
296extern DevPrivateKeyRec sna_window_key;
297
298static inline FbGCPrivate *fb_gc(GCPtr gc)
299{
300	return (FbGCPrivate *)__get_private(gc, sna_gc_key);
301}
302
303static inline PixmapPtr fbGetWindowPixmap(WindowPtr window)
304{
305	return *(PixmapPtr *)__get_private(window, sna_window_key);
306}
307
308#ifdef ROOTLESS
309#define __fbPixDrawableX(p)	((p)->drawable.x)
310#define __fbPixDrawableY(p)	((p)->drawable.y)
311#else
312#define __fbPixDrawableX(p)	0
313#define __fbPixDrawableY(p)	0
314#endif
315
316#ifdef COMPOSITE
317#define __fbPixOffXWin(p)	(__fbPixDrawableX(p) - (p)->screen_x)
318#define __fbPixOffYWin(p)	(__fbPixDrawableY(p) - (p)->screen_y)
319#else
320#define __fbPixOffXWin(p)	(__fbPixDrawableX(p))
321#define __fbPixOffYWin(p)	(__fbPixDrawableY(p))
322#endif
323#define __fbPixOffXPix(p)	(__fbPixDrawableX(p))
324#define __fbPixOffYPix(p)	(__fbPixDrawableY(p))
325
326#define fbGetDrawablePixmap(drawable, pixmap, xoff, yoff) {		\
327    if ((drawable)->type != DRAWABLE_PIXMAP) {				\
328	(pixmap) = fbGetWindowPixmap((WindowPtr)drawable);		\
329	(xoff) = __fbPixOffXWin(pixmap);				\
330	(yoff) = __fbPixOffYWin(pixmap);				\
331    } else {								\
332	(pixmap) = (PixmapPtr) (drawable);				\
333	(xoff) = __fbPixOffXPix(pixmap);				\
334	(yoff) = __fbPixOffYPix(pixmap);				\
335    }									\
336}
337
338#define fbGetPixmapBitsData(pixmap, pointer, stride, bpp) {		\
339    (pointer) = (FbBits *) (pixmap)->devPrivate.ptr;			\
340    (stride) = ((int) (pixmap)->devKind) / sizeof (FbBits); (void)(stride);\
341    (bpp) = (pixmap)->drawable.bitsPerPixel;  (void)(bpp);		\
342}
343
344#define fbGetPixmapStipData(pixmap, pointer, stride, bpp) {		\
345    (pointer) = (FbStip *) (pixmap)->devPrivate.ptr;			\
346    (stride) = ((int) (pixmap)->devKind) / sizeof (FbStip); (void)(stride);\
347    (bpp) = (pixmap)->drawable.bitsPerPixel;  (void)(bpp);		\
348}
349
350#define fbGetDrawable(drawable, pointer, stride, bpp, xoff, yoff) {	\
351    PixmapPtr   _pPix;							\
352    fbGetDrawablePixmap(drawable, _pPix, xoff, yoff);			\
353    fbGetPixmapBitsData(_pPix, pointer, stride, bpp);			\
354}
355
356#define fbGetStipDrawable(drawable, pointer, stride, bpp, xoff, yoff) {	\
357    PixmapPtr   _pPix;							\
358    fbGetDrawablePixmap(drawable, _pPix, xoff, yoff);			\
359    fbGetPixmapStipData(_pPix, pointer, stride, bpp);			\
360}
361
362/*
363 * XFree86 empties the root BorderClip when the VT is inactive,
364 * here's a macro which uses that to disable GetImage and GetSpans
365 */
366
367#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,10,0,0,0)
368#define fbWindowEnabled(pWin) \
369	RegionNotEmpty(&(pWin)->drawable.pScreen->root->borderClip)
370#else
371#define fbWindowEnabled(pWin) \
372	RegionNotEmpty(&WindowTable[(pWin)->drawable.pScreen->myNum]->borderClip)
373#endif
374#define fbDrawableEnabled(drawable) \
375    ((drawable)->type == DRAWABLE_PIXMAP ? \
376     TRUE : fbWindowEnabled((WindowPtr) drawable))
377
378#define FbPowerOfTwo(w)	    (((w) & ((w) - 1)) == 0)
379/*
380 * Accelerated tiles are power of 2 width <= FB_UNIT
381 */
382#define FbEvenTile(w)	    ((w) <= FB_UNIT && FbPowerOfTwo(w))
383/*
384 * Accelerated stipples are power of 2 width and <= FB_UNIT/dstBpp
385 * with dstBpp a power of 2 as well
386 */
387#define FbEvenStip(w,bpp)   ((w) * (bpp) <= FB_UNIT && FbPowerOfTwo(w) && FbPowerOfTwo(bpp))
388
389inline static int16_t fbBound(int16_t a, uint16_t b)
390{
391	int v = (int)a + (int)b;
392	if (v > MAXSHORT)
393		return MAXSHORT;
394	return v;
395}
396
397extern void
398fbPolyArc(DrawablePtr drawable, GCPtr gc, int narcs, xArc * parcs);
399
400extern void
401fbBlt(FbBits *src, FbStride srcStride, int srcX,
402      FbBits *dst, FbStride dstStride, int dstX,
403      int width, int height,
404      int alu, FbBits pm, int bpp,
405      Bool reverse, Bool upsidedown);
406
407#if FB_STIP_SHIFT == FB_SHIFT
408static inline void
409fbBltStip(FbStip *src, FbStride srcStride, int srcX,
410	  FbStip *dst, FbStride dstStride, int dstX,
411	  int width, int height, int alu, FbBits pm, int bpp)
412{
413	fbBlt((FbBits *)src, srcStride, srcX,
414	      (FbBits *)dst, dstStride, dstX,
415	      width, height, alu, pm, bpp,
416	      FALSE, FALSE);
417}
418#else
419#error FB_STIP_SHIFT must equal FB_SHIFT
420#endif
421
422extern void
423fbBltOne(FbStip *src, FbStride srcStride, int srcX,
424         FbBits *dst, FbStride dstStride, int dstX,
425         int dstBpp, int width, int height,
426	 FbBits fgand, FbBits fbxor, FbBits bgand, FbBits bgxor);
427
428extern void
429fbBltPlane(FbBits *src, FbStride srcStride, int srcX, int srcBpp,
430           FbStip *dst, FbStride dstStride, int dstX,
431           int width, int height,
432           FbStip fgand, FbStip fgxor, FbStip bgand, FbStip bgxor,
433	   Pixel planeMask);
434
435extern void
436fbCopyNtoN(DrawablePtr src, DrawablePtr dst, GCPtr gc,
437           BoxPtr pbox, int nbox,
438           int dx, int dy,
439           Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
440
441extern void
442fbCopy1toN(DrawablePtr src, DrawablePtr dst, GCPtr gc,
443           BoxPtr pbox, int nbox,
444           int dx, int dy,
445           Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
446
447extern void
448fbCopyNto1(DrawablePtr src, DrawablePtr dst, GCPtr gc,
449           BoxPtr pbox, int nbox,
450           int dx, int dy,
451           Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
452
453extern RegionPtr
454fbCopyArea(DrawablePtr src, DrawablePtr dst, GCPtr gc,
455	   int sx, int sy,
456	   int width, int height,
457	   int dx, int dy);
458
459extern RegionPtr
460fbCopyPlane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
461	    int sx, int sy,
462	    int width, int height,
463	    int dx, int dy,
464	    unsigned long bitplane);
465
466extern void
467fbFill(DrawablePtr drawable, GCPtr gc, int x, int y, int width, int height);
468
469extern void
470fbSolidBoxClipped(DrawablePtr drawable, GCPtr gc,
471                  int x1, int y1, int x2, int y2);
472
473extern void
474fbPolyFillRect(DrawablePtr drawable, GCPtr gc, int n, xRectangle *rec);
475
476extern void
477fbFillSpans(DrawablePtr drawable, GCPtr gc,
478            int n, DDXPointPtr pt, int *width, int fSorted);
479
480extern void
481fbPadPixmap(PixmapPtr pPixmap);
482
483extern void
484fbValidateGC(GCPtr gc, unsigned long changes, DrawablePtr drawable);
485
486extern void
487fbGetSpans(DrawablePtr drawable, int wMax,
488           DDXPointPtr pt, int *width, int n, char *dst);
489
490extern void
491fbPolyGlyphBlt(DrawablePtr drawable, GCPtr gc, int x, int y,
492               unsigned int n, CharInfoPtr *info, pointer glyphs);
493
494extern void
495fbImageGlyphBlt(DrawablePtr drawable, GCPtr gc, int x, int y,
496                unsigned int n, CharInfoPtr *info, pointer glyphs);
497
498extern void
499fbPutImage(DrawablePtr drawable, GCPtr gc, int depth,
500           int x, int y, int w, int h,
501	   int leftPad, int format, char *image);
502
503extern void
504fbPutXYImage(DrawablePtr drawable, GCPtr gc,
505             FbBits fg, FbBits bg, FbBits pm,
506             int alu, Bool opaque,
507             int x, int y, int width, int height,
508	     FbStip * src, FbStride srcStride, int srcX);
509
510extern void
511fbGetImage(DrawablePtr drawable,
512           int x, int y, int w, int h,
513	   unsigned int format, unsigned long planeMask, char *d);
514
515extern void
516fbPolyLine(DrawablePtr drawable, GCPtr gc, int mode, int n, DDXPointPtr pt);
517
518extern void
519fbFixCoordModePrevious(int n, DDXPointPtr pt);
520
521extern void
522fbPolySegment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg);
523
524extern RegionPtr
525fbBitmapToRegion(PixmapPtr pixmap);
526
527extern void
528fbPolyPoint(DrawablePtr drawable, GCPtr gc,
529	    int mode, int n, xPoint *pt,
530	    unsigned flags);
531
532extern void
533fbPushImage(DrawablePtr drawable, GCPtr gc,
534            FbStip *src, FbStride srcStride, int srcX,
535	    int x, int y, int width, int height);
536
537extern void
538fbPushPixels(GCPtr gc, PixmapPtr pBitmap, DrawablePtr drawable,
539	     int dx, int dy, int xOrg, int yOrg);
540
541extern void
542fbSetSpans(DrawablePtr drawable, GCPtr gc,
543           char *src, DDXPointPtr pt, int *width, int n, int fSorted);
544
545extern void
546fbSegment(DrawablePtr drawable, GCPtr gc,
547          int xa, int ya, int xb, int yb,
548	  bool drawLast, int *dashOffset);
549
550extern void
551fbSegment1(DrawablePtr drawable, GCPtr gc, const BoxRec *clip,
552          int xa, int ya, int xb, int yb,
553	  bool drawLast, int *dashOffset);
554
555extern void
556fbTransparentSpan(FbBits * dst, FbBits stip, FbBits fgxor, int n);
557
558extern void
559fbStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
560          int width, int height,
561          FbStip *stip, FbStride stipStride,
562          int stipWidth, int stipHeight,
563          Bool even,
564          FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
565	  int xRot, int yRot);
566
567extern void
568fbTile(FbBits *dst, FbStride dstStride, int dstX, int width, int height,
569       FbBits *tile, FbStride tileStride, int tileWidth, int tileHeight,
570       int alu, FbBits pm, int bpp,
571       int xRot, int yRot);
572
573extern FbBits fbReplicatePixel(Pixel p, int bpp);
574
575#endif  /* FB_H */
576