Пример #1
0
/*
 * Return the full scan size for a bitmap.
 *
 * Based on Wine, Utils.c and Windows Graphics Prog pg 595, SDK amvideo.h.
 */
UINT
FASTCALL
DIB_BitmapMaxBitsSize(
    PBITMAPINFO Info,
    UINT ScanLines)
{
    UINT Ret;

    if (!Info)
        return 0;

    if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
    {
        PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER) Info;
        Ret = WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes,
                Core->bcBitCount) * ScanLines;
    }
    else /* assume BITMAPINFOHEADER */
    {
        if ((Info->bmiHeader.biCompression == BI_RGB) || (Info->bmiHeader.biCompression == BI_BITFIELDS))
        {
            Ret = WIDTH_BYTES_ALIGN32(
                    Info->bmiHeader.biWidth * Info->bmiHeader.biPlanes,
                    Info->bmiHeader.biBitCount) * ScanLines;
        }
        else
        {
            Ret = Info->bmiHeader.biSizeImage;
        }
    }
    return Ret;
}
Пример #2
0
/*
 * @implemented
 */
int
WINAPI
GdiGetBitmapBitsSize(
    BITMAPINFO *lpbmi)
{
    UINT Ret;

    if (!lpbmi)
        return 0;

    if (lpbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
    {
        PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER) lpbmi;
        Ret =
        WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes,
                Core->bcBitCount) * Core->bcHeight;
    }
    else /* assume BITMAPINFOHEADER */
    {
        if (!(lpbmi->bmiHeader.biCompression) || (lpbmi->bmiHeader.biCompression == BI_BITFIELDS))
        {
            Ret = WIDTH_BYTES_ALIGN32(
                    lpbmi->bmiHeader.biWidth * lpbmi->bmiHeader.biPlanes,
                    lpbmi->bmiHeader.biBitCount) * abs(lpbmi->bmiHeader.biHeight);
        }
        else
        {
            Ret = lpbmi->bmiHeader.biSizeImage;
        }
    }
    return Ret;
}
Пример #3
0
/**
 * This function is not exported, because it makes no sense for
 * The driver to punt back to this function */
BOOL
APIENTRY
EngRealizeBrush(
    BRUSHOBJ *pbo,
    SURFOBJ  *psoDst,
    SURFOBJ  *psoPattern,
    SURFOBJ  *psoMask,
    XLATEOBJ *pxlo,
    ULONG    iHatch)
{
    EBRUSHOBJ *pebo;
    HBITMAP hbmpRealize;
    SURFOBJ *psoRealize;
    PSURFACE psurfRealize;
    POINTL ptlSrc = {0, 0};
    RECTL rclDest;
    ULONG lWidth;

    /* Calculate width in bytes of the realized brush */
    lWidth = WIDTH_BYTES_ALIGN32(psoPattern->sizlBitmap.cx,
                                  BitsPerFormat(psoDst->iBitmapFormat));

    /* Allocate a bitmap */
    hbmpRealize = EngCreateBitmap(psoPattern->sizlBitmap,
                                  lWidth,
                                  psoDst->iBitmapFormat,
                                  BMF_NOZEROINIT,
                                  NULL);
    if (!hbmpRealize)
    {
        return FALSE;
    }

    /* Lock the bitmap */
    psurfRealize = SURFACE_ShareLockSurface(hbmpRealize);

    /* Already delete the pattern bitmap (will be kept until dereferenced) */
    EngDeleteSurface((HSURF)hbmpRealize);

    if (!psurfRealize)
    {
        return FALSE;
    }

    /* Copy the bits to the new format bitmap */
    rclDest.left = rclDest.top = 0;
    rclDest.right = psoPattern->sizlBitmap.cx;
    rclDest.bottom = psoPattern->sizlBitmap.cy;
    psoRealize = &psurfRealize->SurfObj;
    EngCopyBits(psoRealize, psoPattern, NULL, pxlo, &rclDest, &ptlSrc);


    pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
    pebo->pengbrush = (PVOID)psurfRealize;

    return TRUE;
}
Пример #4
0
static void
sw_MapRenderbuffer(struct gl_context *ctx,
                   struct gl_renderbuffer *rb,
                   GLuint x, GLuint y, GLuint w, GLuint h,
                   GLbitfield mode,
                   GLubyte **mapOut, GLint *rowStrideOut)
{
    if(rb->ClassID == SW_FRONT_RENDERBUFFER_CLASS)
    {
        /* This is our front buffer */
        struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb;
        struct sw_framebuffer* fb = CONTAINING_RECORD(srb, struct sw_framebuffer, frontbuffer);
        /* Set the stride */
        *rowStrideOut = WIDTH_BYTES_ALIGN32(rb->Width, pixel_formats[fb->format_index].color_bits);
        /* Remember where we "mapped" */
        srb->x = x; srb->y = y; srb->w = w; srb->h = h;
        /* Remember if we should write it later */
        srb->write = !!(mode & GL_MAP_WRITE_BIT);
        /* Get the bits, if needed */
        if(mode & GL_MAP_READ_BIT)
        {
            BitBlt(srb->hdcmem, srb->x, srb->y, srb->w, srb->h,
                IntGetCurrentDC(), srb->x, srb->y, SRCCOPY);
        }
        /* And return it */
        *mapOut = (BYTE*)srb->swrast.Buffer + *rowStrideOut*y + x*pixel_formats[fb->format_index].color_bits/8;
        return;
    }
    
    if(rb->ClassID == SW_BACK_RENDERBUFFER_CLASS)
    {
        /* This is our front buffer */
        struct swrast_renderbuffer* srb = (struct swrast_renderbuffer*)rb;
        const GLuint bpp = _mesa_get_format_bytes(rb->Format);
        /* Set the stride */
        *rowStrideOut = srb->RowStride;
        *mapOut = (BYTE*)srb->Buffer + srb->RowStride*y + x*bpp;
        return;
    }
    
    /* Let mesa rasterizer take care of this */
    _swrast_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode,
                                  mapOut, rowStrideOut);
}
Пример #5
0
/* Renderbuffer routines */
static GLboolean
sw_bb_renderbuffer_storage(struct gl_context* ctx, struct gl_renderbuffer *rb,
                          GLenum internalFormat,
                          GLuint width, GLuint height)
{
    struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
    struct sw_framebuffer* fb = CONTAINING_RECORD(srb, struct sw_framebuffer, backbuffer);
    UINT widthBytes = WIDTH_BYTES_ALIGN32(width, pixel_formats[fb->format_index].color_bits); 
    srb->Base.Format = pixel_formats[fb->format_index].mesa;

    if(srb->Buffer)
        srb->Buffer = HeapReAlloc(GetProcessHeap(), 0, srb->Buffer, widthBytes*height);
    else
        srb->Buffer = HeapAlloc(GetProcessHeap(), 0, widthBytes*height);
    if(!srb->Buffer)
    {
        srb->Base.Format = MESA_FORMAT_NONE;
        return GL_FALSE;
    }
    srb->Base.Width = width;
    srb->Base.Height = height;
    srb->RowStride = widthBytes;
    return GL_TRUE;
}
Пример #6
0
/*
 * @implemented
 */
ULONG
APIENTRY
EngSetPointerShape(
    _In_ SURFOBJ *pso,
    _In_opt_ SURFOBJ *psoMask,
    _In_opt_ SURFOBJ *psoColor,
    _In_opt_ XLATEOBJ *pxlo,
    _In_ LONG xHot,
    _In_ LONG yHot,
    _In_ LONG x,
    _In_ LONG y,
    _In_ RECTL *prcl,
    _In_ FLONG fl)
{
    PDEVOBJ *ppdev;
    GDIPOINTER *pgp;
    LONG lDelta = 0;
    HBITMAP hbmSave = NULL, hbmColor = NULL, hbmMask = NULL;
    PSURFACE psurfSave = NULL, psurfColor = NULL, psurfMask = NULL;
    RECTL rectl;
    SIZEL sizel = {0, 0};

    ASSERT(pso);

    ppdev = GDIDEV(pso);
    pgp = &ppdev->Pointer;

    /* Handle the case where we have no XLATEOBJ */
    if (pxlo == NULL)
        pxlo = &gexloTrivial.xlo;

    /* Do we have any bitmap at all? */
    if (psoColor || psoMask)
    {
        /* Get the size of the new pointer */
        if (psoColor)
        {
            sizel.cx = psoColor->sizlBitmap.cx;
            sizel.cy = psoColor->sizlBitmap.cy;
        }
        else// if (psoMask)
        {
            sizel.cx = psoMask->sizlBitmap.cx;
            sizel.cy = psoMask->sizlBitmap.cy / 2;
        }

        rectl.left = 0;
        rectl.top = 0;
        rectl.right = sizel.cx;
        rectl.bottom = sizel.cy;

        /* Calculate lDelta for our surfaces. */
        lDelta = WIDTH_BYTES_ALIGN32(sizel.cx,
                                     BitsPerFormat(pso->iBitmapFormat));

        /* Create a bitmap for saving the pixels under the cursor. */
        hbmSave = EngCreateBitmap(sizel,
                                  lDelta,
                                  pso->iBitmapFormat,
                                  BMF_TOPDOWN | BMF_NOZEROINIT,
                                  NULL);
        psurfSave = SURFACE_ShareLockSurface(hbmSave);
        if (!psurfSave) goto failure;
    }

    if (psoColor)
    {
        if (fl & SPS_ALPHA)
        {
            /* Always store the alpha cursor in RGB. */
            EXLATEOBJ exloSrcRGB;
            PEXLATEOBJ pexlo;

            pexlo = CONTAINING_RECORD(pxlo, EXLATEOBJ, xlo);
            EXLATEOBJ_vInitialize(&exloSrcRGB, pexlo->ppalSrc, &gpalRGB, 0, 0, 0);

            hbmColor = EngCreateBitmap(psoColor->sizlBitmap,
                WIDTH_BYTES_ALIGN32(sizel.cx, 32),
                BMF_32BPP,
                BMF_TOPDOWN | BMF_NOZEROINIT,
                NULL);
            psurfColor = SURFACE_ShareLockSurface(hbmColor);
            if (!psurfColor) goto failure;

            /* Now copy the given bitmap. */
            rectl.bottom = psoColor->sizlBitmap.cy;
            IntEngCopyBits(&psurfColor->SurfObj,
                           psoColor,
                           NULL,
                           &exloSrcRGB.xlo,
                           &rectl,
                           (POINTL*)&rectl);

            EXLATEOBJ_vCleanup(&exloSrcRGB);
        }
        else
        {
            /* Color bitmap must have the same format as the dest surface */
            if (psoColor->iBitmapFormat != pso->iBitmapFormat)
            {
                DPRINT1("Screen surface and cursor color bitmap format don't match!.\n");
                goto failure;
            }

            /* Create a bitmap to copy the color bitmap to */
            hbmColor = EngCreateBitmap(psoColor->sizlBitmap,
                               lDelta,
                               pso->iBitmapFormat,
                               BMF_TOPDOWN | BMF_NOZEROINIT,
                               NULL);
            psurfColor = SURFACE_ShareLockSurface(hbmColor);
            if (!psurfColor) goto failure;

            /* Now copy the given bitmap. */
            rectl.bottom = psoColor->sizlBitmap.cy;
            IntEngCopyBits(&psurfColor->SurfObj,
                           psoColor,
                           NULL,
                           pxlo,
                           &rectl,
                           (POINTL*)&rectl);
        }

    }

    /* Create a mask surface */
    if (psoMask)
    {
        EXLATEOBJ exlo;
        PPALETTE ppal;

        lDelta = WIDTH_BYTES_ALIGN32(sizel.cx, BitsPerFormat(pso->iBitmapFormat));

        /* Create a bitmap for the mask */
        hbmMask = EngCreateBitmap(psoMask->sizlBitmap,
                                  lDelta,
                                  pso->iBitmapFormat,
                                  BMF_TOPDOWN | BMF_NOZEROINIT,
                                  NULL);
        psurfMask = SURFACE_ShareLockSurface(hbmMask);
        if (!psurfMask) goto failure;

        /* Initialize an EXLATEOBJ */
        ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
        EXLATEOBJ_vInitialize(&exlo,
                              gppalMono,
                              ppal,
                              0,
                              RGB(0xff,0xff,0xff),
                              RGB(0,0,0));

        /* Copy the mask bitmap */
        rectl.bottom = psoMask->sizlBitmap.cy;
        IntEngCopyBits(&psurfMask->SurfObj,
                       psoMask,
                       NULL,
                       &exlo.xlo,
                       &rectl,
                       (POINTL*)&rectl);

        /* Cleanup */
        EXLATEOBJ_vCleanup(&exlo);
        if (ppal) PALETTE_ShareUnlockPalette(ppal);
    }

    /* Hide mouse pointer */
    IntHideMousePointer(ppdev, pso);

    /* Free old color bitmap */
    if (pgp->psurfColor)
    {
        EngDeleteSurface(pgp->psurfColor->BaseObject.hHmgr);
        SURFACE_ShareUnlockSurface(pgp->psurfColor);
        pgp->psurfColor = NULL;
    }

    /* Free old mask bitmap */
    if (pgp->psurfMask)
    {
        EngDeleteSurface(pgp->psurfMask->BaseObject.hHmgr);
        SURFACE_ShareUnlockSurface(pgp->psurfMask);
        pgp->psurfMask = NULL;
    }

    /* Free old save bitmap */
    if (pgp->psurfSave)
    {
        EngDeleteSurface(pgp->psurfSave->BaseObject.hHmgr);
        SURFACE_ShareUnlockSurface(pgp->psurfSave);
        pgp->psurfSave = NULL;
    }

    /* See if we are being asked to hide the pointer. */
    if (psoMask == NULL && psoColor == NULL)
    {
        /* We're done */
        return SPS_ACCEPT_NOEXCLUDE;
    }

    /* Now set the new cursor */
    pgp->psurfColor = psurfColor;
    pgp->psurfMask = psurfMask;
    pgp->psurfSave = psurfSave;
    pgp->HotSpot.x = xHot;
    pgp->HotSpot.y = yHot;
    pgp->Size = sizel;
    pgp->flags = fl;

    if (x != -1)
    {
        ppdev->ptlPointer.x = x;
        ppdev->ptlPointer.y = y;

        IntShowMousePointer(ppdev, pso);

        if (prcl != NULL)
        {
            prcl->left = x - pgp->HotSpot.x;
            prcl->top = y - pgp->HotSpot.x;
            prcl->right = prcl->left + pgp->Size.cx;
            prcl->bottom = prcl->top + pgp->Size.cy;
        }
    }
    else if (prcl != NULL)
    {
        prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
    }

    return SPS_ACCEPT_NOEXCLUDE;

failure:
    /* Cleanup surfaces */
    if (hbmMask) EngDeleteSurface((HSURF)hbmMask);
    if (psurfMask) SURFACE_ShareUnlockSurface(psurfMask);
    if (hbmColor) EngDeleteSurface((HSURF)hbmColor);
    if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
    if (hbmSave) EngDeleteSurface((HSURF)hbmSave);
    if (psurfSave) SURFACE_ShareUnlockSurface(psurfSave);

    return SPS_ERROR;
}
Пример #7
0
BOOL APIENTRY
IntEngEnter(PINTENG_ENTER_LEAVE EnterLeave,
            SURFOBJ *psoDest,
            RECTL *DestRect,
            BOOL ReadOnly,
            POINTL *Translate,
            SURFOBJ **ppsoOutput)
{
  LONG Exchange;
  SIZEL BitmapSize;
  POINTL SrcPoint;
  LONG Width;
  RECTL ClippedDestRect;

  /* Normalize */
  if (DestRect->right < DestRect->left)
    {
    Exchange = DestRect->left;
    DestRect->left = DestRect->right;
    DestRect->right = Exchange;
    }
  if (DestRect->bottom < DestRect->top)
    {
    Exchange = DestRect->top;
    DestRect->top = DestRect->bottom;
    DestRect->bottom = Exchange;
    }

  if (NULL != psoDest && STYPE_BITMAP != psoDest->iType &&
      (NULL == psoDest->pvScan0 || 0 == psoDest->lDelta))
    {
    /* Driver needs to support DrvCopyBits, else we can't do anything */
    SURFACE *psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
    if (!(psurfDest->flags & HOOK_COPYBITS))
    {
      return FALSE;
    }

    /* Allocate a temporary bitmap */
    BitmapSize.cx = DestRect->right - DestRect->left;
    BitmapSize.cy = DestRect->bottom - DestRect->top;
    Width = WIDTH_BYTES_ALIGN32(BitmapSize.cx, BitsPerFormat(psoDest->iBitmapFormat));
    EnterLeave->OutputBitmap = EngCreateBitmap(BitmapSize, Width,
                                               psoDest->iBitmapFormat,
                                               BMF_TOPDOWN | BMF_NOZEROINIT, NULL);

    if (!EnterLeave->OutputBitmap)
      {
      DPRINT1("EngCreateBitmap() failed\n");
      return FALSE;
      }

    *ppsoOutput = EngLockSurface((HSURF)EnterLeave->OutputBitmap);
    if (*ppsoOutput == NULL)
    {
      EngDeleteSurface((HSURF)EnterLeave->OutputBitmap);
      return FALSE;
    }

    EnterLeave->DestRect.left = 0;
    EnterLeave->DestRect.top = 0;
    EnterLeave->DestRect.right = BitmapSize.cx;
    EnterLeave->DestRect.bottom = BitmapSize.cy;
    SrcPoint.x = DestRect->left;
    SrcPoint.y = DestRect->top;
    ClippedDestRect = EnterLeave->DestRect;
    if (SrcPoint.x < 0)
      {
        ClippedDestRect.left -= SrcPoint.x;
        SrcPoint.x = 0;
      }
    if (psoDest->sizlBitmap.cx < SrcPoint.x + ClippedDestRect.right - ClippedDestRect.left)
      {
        ClippedDestRect.right = ClippedDestRect.left + psoDest->sizlBitmap.cx - SrcPoint.x;
      }
    if (SrcPoint.y < 0)
      {
        ClippedDestRect.top -= SrcPoint.y;
        SrcPoint.y = 0;
      }
    if (psoDest->sizlBitmap.cy < SrcPoint.y + ClippedDestRect.bottom - ClippedDestRect.top)
      {
        ClippedDestRect.bottom = ClippedDestRect.top + psoDest->sizlBitmap.cy - SrcPoint.y;
      }
    EnterLeave->TrivialClipObj = EngCreateClip();
    if (EnterLeave->TrivialClipObj == NULL)
    {
      EngUnlockSurface(*ppsoOutput);
      EngDeleteSurface((HSURF)EnterLeave->OutputBitmap);
      return FALSE;
    }
    EnterLeave->TrivialClipObj->iDComplexity = DC_TRIVIAL;
    if (ClippedDestRect.left < (*ppsoOutput)->sizlBitmap.cx &&
        0 <= ClippedDestRect.right &&
        SrcPoint.x < psoDest->sizlBitmap.cx &&
        ClippedDestRect.top <= (*ppsoOutput)->sizlBitmap.cy &&
        0 <= ClippedDestRect.bottom &&
        SrcPoint.y < psoDest->sizlBitmap.cy &&
        ! GDIDEVFUNCS(psoDest).CopyBits(
                                        *ppsoOutput, psoDest,
                                        EnterLeave->TrivialClipObj, NULL,
                                        &ClippedDestRect, &SrcPoint))
      {
          EngDeleteClip(EnterLeave->TrivialClipObj);
          EngUnlockSurface(*ppsoOutput);
          EngDeleteSurface((HSURF)EnterLeave->OutputBitmap);
          return FALSE;
      }
    EnterLeave->DestRect.left = DestRect->left;
    EnterLeave->DestRect.top = DestRect->top;
    EnterLeave->DestRect.right = DestRect->right;
    EnterLeave->DestRect.bottom = DestRect->bottom;
    Translate->x = - DestRect->left;
    Translate->y = - DestRect->top;
    }
  else
    {
    Translate->x = 0;
    Translate->y = 0;
    *ppsoOutput = psoDest;
    }

  if (NULL != *ppsoOutput)
  {
    SURFACE* psurfOutput = CONTAINING_RECORD(*ppsoOutput, SURFACE, SurfObj);
    if (0 != (psurfOutput->flags & HOOK_SYNCHRONIZE))
    {
      if (NULL != GDIDEVFUNCS(*ppsoOutput).SynchronizeSurface)
        {
          GDIDEVFUNCS(*ppsoOutput).SynchronizeSurface(*ppsoOutput, DestRect, 0);
        }
      else if (STYPE_BITMAP == (*ppsoOutput)->iType
               && NULL != GDIDEVFUNCS(*ppsoOutput).Synchronize)
        {
          GDIDEVFUNCS(*ppsoOutput).Synchronize((*ppsoOutput)->dhpdev, DestRect);
        }
    }
  }
  else return FALSE;

  EnterLeave->DestObj = psoDest;
  EnterLeave->OutputObj = *ppsoOutput;
  EnterLeave->ReadOnly = ReadOnly;

  return TRUE;
}
Пример #8
0
HBITMAP
NTAPI
GreCreateBitmapEx(
    _In_ ULONG nWidth,
    _In_ ULONG nHeight,
    _In_ ULONG cjWidthBytes,
    _In_ ULONG iFormat,
    _In_ USHORT fjBitmap,
    _In_ ULONG cjSizeImage,
    _In_opt_ PVOID pvBits,
    _In_ FLONG flags)
{
    PSURFACE psurf;
    HBITMAP hbmp;
    PVOID pvCompressedBits = NULL;

    /* Verify format */
    if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL;

    /* The infamous RLE hack */
    if ((iFormat == BMF_4RLE) || (iFormat == BMF_8RLE))
    {
        pvCompressedBits = pvBits;
        pvBits = NULL;
        iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP;
    }

    /* Allocate a surface */
    psurf = SURFACE_AllocSurface(STYPE_BITMAP,
                                 nWidth,
                                 nHeight,
                                 iFormat,
                                 fjBitmap,
                                 cjWidthBytes,
                                 pvBits);
    if (!psurf)
    {
        DPRINT1("SURFACE_AllocSurface failed.\n");
        return NULL;
    }

    /* The infamous RLE hack */
    if (pvCompressedBits)
    {
        SIZEL sizl;
        LONG lDelta;

        sizl.cx = nWidth;
        sizl.cy = nHeight;
        lDelta = WIDTH_BYTES_ALIGN32(nWidth, gajBitsPerFormat[iFormat]);

        pvBits = psurf->SurfObj.pvBits;
        DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat);
    }

    /* Get the handle for the bitmap */
    hbmp = (HBITMAP)psurf->SurfObj.hsurf;

    /* Mark as API bitmap */
    psurf->flags |= (flags | API_BITMAP);

    /* Unlock the surface and return */
    SURFACE_UnlockSurface(psurf);
    return hbmp;
}
Пример #9
0
PSURFACE
NTAPI
SURFACE_AllocSurface(
    _In_ USHORT iType,
    _In_ ULONG cx,
    _In_ ULONG cy,
    _In_ ULONG iFormat,
    _In_ ULONG fjBitmap,
    _In_opt_ ULONG cjWidth,
    _In_opt_ ULONG cjBufSize,
    _In_opt_ PVOID pvBits)
{
    ULONG cBitsPixel, cjBits, cjObject;
    PSURFACE psurf;
    SURFOBJ *pso;
    PVOID pvSection;

    NT_ASSERT(!pvBits || (iType == STYPE_BITMAP));
    NT_ASSERT((iFormat <= BMF_32BPP) || (cjBufSize != 0));
    NT_ASSERT((LONG)cy > 0);

    /* Verify format */
    if ((iFormat < BMF_1BPP) || (iFormat > BMF_PNG))
    {
        DPRINT1("Invalid bitmap format: %lu\n", iFormat);
        return NULL;
    }

    /* Get bits per pixel from the format */
    cBitsPixel = gajBitsPerFormat[iFormat];

    /* Are bits and a width in bytes given? */
    if (pvBits && cjWidth)
    {
        /* Align the width (Windows compatibility, drivers expect that) */
        cjWidth = WIDTH_BYTES_ALIGN32((cjWidth << 3) / cBitsPixel, cBitsPixel);
    }
    else
    {
        /* Calculate width from the bitmap width in pixels */
        cjWidth = WIDTH_BYTES_ALIGN32(cx, cBitsPixel);
    }

    /* Is this an uncompressed format? */
    if (iFormat <= BMF_32BPP)
    {
        /* Calculate the correct bitmap size in bytes */
        if (!NT_SUCCESS(RtlULongMult(cjWidth, cy, &cjBits)))
        {
            DPRINT1("Overflow calculating size: cjWidth %lu, cy %lu\n",
                    cjWidth, cy);
            return NULL;
        }

        /* Did we get a buffer and size? */
        if ((pvBits != NULL) && (cjBufSize != 0))
        {
            /* Make sure the buffer is large enough */
            if (cjBufSize < cjBits)
            {
                DPRINT1("Buffer is too small, required: %lu, got %lu\n",
                        cjBits, cjBufSize);
                return NULL;
            }
        }
    }
    else
    {
        /* Compressed format, use the provided size */
        NT_ASSERT(cjBufSize != 0);
        cjBits = cjBufSize;
    }

    /* Check if we need an extra large object */
    if ((iType == STYPE_BITMAP) && (pvBits == NULL) &&
        !(fjBitmap & BMF_USERMEM) && !(fjBitmap & BMF_KMSECTION))
    {
        /* Allocate an object large enough to hold the bits */
        cjObject = sizeof(SURFACE) + cjBits;
    }
    else
    {
        /* Otherwise just allocate the SURFACE structure */
        cjObject = sizeof(SURFACE);
    }

    /* Check for arithmetic overflow */
    if (cjObject < sizeof(SURFACE))
    {
        /* Fail! */
        DPRINT1("Overflow calculating cjObject: cjBits %lu\n", cjBits);
        return NULL;
    }

    /* Allocate a SURFACE object */
    psurf = (PSURFACE)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_BITMAP, cjObject);
    if (!psurf)
    {
        return NULL;
    }

    /* Initialize the basic fields */
    pso = &psurf->SurfObj;
    pso->hsurf = psurf->BaseObject.hHmgr;
    pso->sizlBitmap.cx = cx;
    pso->sizlBitmap.cy = cy;
    pso->iBitmapFormat = iFormat;
    pso->iType = iType;
    pso->fjBitmap = (USHORT)fjBitmap;
    pso->iUniq = InterlockedIncrement(&giUniqueSurface);
    pso->cjBits = cjBits;

    /* Check if we need a bitmap buffer */
    if (iType == STYPE_BITMAP)
    {
        /* Check if we got one or if we need to allocate one */
        if (pvBits != NULL)
        {
            /* Use the caller provided buffer */
            pso->pvBits = pvBits;
        }
        else if (fjBitmap & BMF_USERMEM)
        {
            /* User mode memory was requested */
            pso->pvBits = EngAllocUserMem(cjBits, 0);

            /* Check for failure */
            if (!pso->pvBits)
            {
                GDIOBJ_vDeleteObject(&psurf->BaseObject);
                return NULL;
            }
        }
        else if (fjBitmap & BMF_KMSECTION)
        {
            /* Use a kernel mode section */
            pso->pvBits = EngAllocSectionMem(&pvSection,
                                             (fjBitmap & BMF_NOZEROINIT) ?
                                                 0 : FL_ZERO_MEMORY,
                                             cjBits, TAG_DIB);

            /* Check for failure */
            if (!pso->pvBits)
            {
                GDIOBJ_vDeleteObject(&psurf->BaseObject);
                return NULL;
            }

            /* Free the section already, but keep the mapping */
            EngFreeSectionMem(pvSection, NULL);
        }
        else
        {
            /* Buffer is after the object */
            pso->pvBits = psurf + 1;

            /* Zero the buffer, except requested otherwise */
            if (!(fjBitmap & BMF_NOZEROINIT))
            {
                RtlZeroMemory(pso->pvBits, cjBits);
            }
        }

        /* Set pvScan0 and lDelta */
        if (fjBitmap & BMF_TOPDOWN)
        {
            /* Topdown is the normal way */
            pso->pvScan0 = pso->pvBits;
            pso->lDelta = cjWidth;
        }
        else
        {
            /* Inversed bitmap (bottom up) */
            pso->pvScan0 = ((PCHAR)pso->pvBits + pso->cjBits - cjWidth);
            pso->lDelta = -(LONG)cjWidth;
        }
    }
    else
    {
        /* There are no bitmap bits */
        pso->pvScan0 = pso->pvBits = NULL;
        pso->lDelta = 0;
    }

    /* Assign a default palette and increment its reference count */
    SURFACE_vSetPalette(psurf, appalSurfaceDefault[iFormat]);

    return psurf;
}