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