/******************************Module*Header*******************************\ * Module Name: brushapi.cxx * * * * Contains all the various GDI versions of Brush creation. * * * * Created: 06-Nov-1990 14:46:03 * * Author: Walt Moore [waltm] * * * * Copyright (c) 1990-1999 Microsoft Corporation * \**************************************************************************/ #include "precomp.hxx" #include "engline.hxx" // Default wide-line style arrays: ULONG gaulGeometricDot[] = { 1, 1 }; ULONG gaulGeometricDash[] = { 3, 1 }; ULONG gaulGeometricDashDot[] = { 3, 1, 1, 1 }; ULONG gaulGeometricDashDotDot[] = { 3, 1, 1, 1, 1, 1 }; // Default cosmetic style arrays (must all sum to 8): LONG_FLOAT galeCosmeticDot[] = { {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1} }; LONG_FLOAT galeCosmeticDash[] = { {6}, {2} }; LONG_FLOAT galeCosmeticDashDot[] = { {3}, {2}, {1}, {2} }; LONG_FLOAT galeCosmeticDashDotDot[] = { {3}, {1}, {1}, {1}, {1}, {1} }; /**************************************************************************\ * hCreateSolidBrushInternal(clrr, bPen) * * Creates a solid brush. Whether or not the brush is solid or dithered * will depend on what mode the DC is in at realization time. * \**************************************************************************/ HBRUSH hCreateSolidBrushInternal( COLORREF clrr, BOOL bPen, HBRUSH hbr, BOOL bSharedMem) { HBRUSH hbrReturn = NULL; if (hbr) { // // If an already created brush is passed, just try to set it. // if (GreSetSolidBrushInternal(hbr,clrr,bPen,FALSE)) { hbrReturn = hbr; } } else { BRUSHMEMOBJ brmo(clrr, HS_DITHEREDCLR, bPen, bSharedMem); if (brmo.bValid()) { brmo.vKeepIt(); brmo.vEnableDither(); hbrReturn = brmo.hbrush(); } } return hbrReturn; } /**************************************************************************\ * GreCreateSolidBrush() * \**************************************************************************/ HBRUSH GreCreateSolidBrush( COLORREF clrr) { return(hCreateSolidBrushInternal(clrr,FALSE,NULL,FALSE)); } /**************************************************************************\ * NtGdiCreateSolidBrush() * \**************************************************************************/ HBRUSH APIENTRY NtGdiCreateSolidBrush( COLORREF cr, HBRUSH hbr ) { HBRUSH hbrush; hbrush = hCreateSolidBrushInternal(cr, FALSE, hbr, TRUE); return (hbrush); } /**************************************************************************\ * hCreateHatchBrushInternal(ulStyle, clrr, bPen) * * Creates a hatch brush. * * History: * 07-Jun-1995 -by- Andre Vachon [andreva] * Wrote it. \**************************************************************************/ HBRUSH hCreateHatchBrushInternal( ULONG ulStyle, COLORREF clrr, BOOL bPen) { HBRUSH hbr = NULL; if (ulStyle <= HS_API_MAX-1) { BRUSHMEMOBJ brmo(clrr, ulStyle, bPen, FALSE); if (brmo.bValid()) { brmo.vKeepIt(); hbr = brmo.hbrush(); } } return hbr; } /**************************************************************************\ * NtGdiCreateHatchBrushInternal(ulStyle, clrr, bPen) * \**************************************************************************/ HBRUSH APIENTRY NtGdiCreateHatchBrushInternal( ULONG ulStyle, COLORREF cr, BOOL bPen ) { HBRUSH hbrush; hbrush = hCreateHatchBrushInternal (ulStyle, cr, bPen); return (hbrush); } /******************************Public*Routine******************************\ * NtGdiCreatePatternBrushInternal() * * History: * 01-Nov-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ HBRUSH APIENTRY NtGdiCreatePatternBrushInternal( HBITMAP hbm, BOOL bPen, BOOL b8X8 ) { HBRUSH hbrush; hbrush = GreCreatePatternBrushInternal(hbm,bPen,b8X8); return (hbrush); } /******************************Public*Routine******************************\ * NtGdiCreateDIBBrush() * * History: * 01-Nov-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ HBRUSH APIENTRY NtGdiCreateDIBBrush( PVOID pv, FLONG fl, UINT cj, BOOL b8X8, BOOL bPen, PVOID pClient ) { HBRUSH hbrRet; PVOID pvTmp; pvTmp = AllocFreeTmpBuffer(cj); if (pvTmp) { hbrRet = (HBRUSH)1; __try { ProbeForRead(pv,cj, sizeof(BYTE)); RtlCopyMemory(pvTmp,pv,cj); } __except(EXCEPTION_EXECUTE_HANDLER) { // SetLastError(GetExceptionCode()); hbrRet = (HBRUSH)0; } if (hbrRet) { hbrRet = GreCreateDIBBrush(pvTmp,fl,cj,b8X8,bPen,pClient); } FreeTmpBuffer(pvTmp); } else { // SetLastError(); hbrRet = (HBRUSH)0; } return(hbrRet); } /**************************************************************************\ * GreCreatePatternBrushInternal(hbm, bPen) * * Creates a pattern brush from the bitmap passed in. * * History: * Mon 24-Jun-1991 -by- Patrick Haluptzok [patrickh] * Wrote it. \**************************************************************************/ HBRUSH GreCreatePatternBrushInternal( HBITMAP hbm, BOOL bPen, BOOL b8X8) { HBRUSH hbrReturn = (HBRUSH) 0; SURFREF SurfBmo((HSURF)hbm); if (SurfBmo.bValid()) { if (SurfBmo.ps->bApiBitmap()) { HBITMAP hbmClone; if (b8X8) hbmClone = hbmCreateClone(SurfBmo.ps,8,8); else hbmClone = hbmCreateClone(SurfBmo.ps,0,0); if (hbmClone != (HBITMAP) 0) { XEPALOBJ pal(SurfBmo.ps->ppal()); BRUSHMEMOBJ brmo(hbmClone, hbm, pal.bIsMonochrome(), DIB_RGB_COLORS, BR_IS_BITMAP, bPen); if (brmo.bValid()) { hbrReturn = brmo.hbrush(); brmo.vKeepIt(); } // hmgr logs error code } // hmgr logs error code } else { WARNING("GreCreatePatternBrushInternal: Invalid surface"); SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); } } else { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); } return(hbrReturn); } HBRUSH GreCreatePatternBrush(HBITMAP hbm) { return(GreCreatePatternBrushInternal(hbm,FALSE,FALSE)); } /******************************Public*Routine******************************\ * GreCreateDIBBrush * * Creates a DIB pattern brush. * * History: * 02-Jun-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ HBRUSH GreCreateDIBBrush(PVOID pv, FLONG fl, UINT cjMax, BOOL b8X8, BOOL bPen, PVOID pClient) { // Validate your parameters. if ((pv == (PVOID) 0) || (cjMax < sizeof(BITMAPINFOHEADER)) || (((BITMAPINFOHEADER *) pv)->biSize > cjMax) || ((fl != DIB_PAL_INDICES) && (fl != DIB_PAL_COLORS) && (fl != DIB_RGB_COLORS))) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return((HBRUSH) 0); } // Compute offset to the bits UINT cjHeader = ((BITMAPINFOHEADER *) pv)->biSize; PBYTE pjBits = ((PBYTE) pv) + cjHeader; PUSHORT pusIndices; UINT uiBits,cSize,uiCompression; UINT cPalEntriesTotal; LPBITMAPINFO pbmiTmp = NULL; UINT cPalEntryMax; uiBits = ((BITMAPINFOHEADER *) pv)->biBitCount; pusIndices = (PUSHORT) pjBits; cSize = sizeof(RGBQUAD); cPalEntriesTotal = (UINT) ((BITMAPINFOHEADER *) pv)->biClrUsed; uiCompression = ((BITMAPINFOHEADER *) pv)->biCompression; // Check proper settings for compression. if (uiCompression == BI_BITFIELDS) { cPalEntriesTotal = 3; if (fl == DIB_PAL_COLORS) fl = DIB_RGB_COLORS; if ((uiBits != 16) && (uiBits != 32)) { WARNING("CreateDIBPatternBrush given invalid data for BI_BITFIELDS\n"); return((HBRUSH) 0); } } else if (uiCompression == BI_RGB) { switch(uiBits) { case 1: cPalEntryMax = 2; break; case 4: cPalEntryMax = 16; break; case 8: cPalEntryMax = 256; break; case 16: case 24: case 32: cPalEntryMax = cPalEntriesTotal = 0; // Win3.1 ignores the DIB_PAL_COLORS flag when non-indexed passed in. if (fl == DIB_PAL_COLORS) fl = DIB_RGB_COLORS; break; default: WARNING("GreCreateDIBPatternBrushPt failed because of invalid bit count BI_RGB"); return((HBRUSH) 0); } if (cPalEntriesTotal == 0) { cPalEntriesTotal = cPalEntryMax; } else cPalEntriesTotal = MIN(cPalEntryMax, cPalEntriesTotal); } else if (uiCompression == BI_RLE4) { if (uiBits != 4) { WARNING("CreateDIBrush RLE4 invalid bpp\n"); return((HBRUSH) 0); } if (cPalEntriesTotal == 0) { cPalEntriesTotal = 16; } } else if (uiCompression == BI_RLE8) { if (uiBits != 8) { WARNING("CreateDIBrush RLE8 invalid bpp\n"); return((HBRUSH) 0); } if (cPalEntriesTotal == 0) { cPalEntriesTotal = 256; } } else { // We don't support any other compressions for creating a brush on NT. WARNING("Unknown Compression passed in - failed CreateDIBPatternBrush\n"); return((HBRUSH) 0); } // Check for the DIB_PAL_COLORS case. if (fl == DIB_PAL_COLORS) cSize = sizeof(USHORT); else if (fl == DIB_PAL_INDICES) cSize = 0; // Validate that buffer is large enough to include color table. Guarantees // that pjBits is within the bounds of the pv buffer passed in. UINT cjColorTable = (((cSize * cPalEntriesTotal) + 3) & ~3); if (cjColorTable > (cjMax - cjHeader)) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(0); } pjBits += cjColorTable; // now, pjBits = pv + cjHeader + cjColorTable // // Sundown: safe to truncate to INT since pjBits - pv will not exceed 4GB // (validation above ensures that difference is <= cjMax) // INT cjBits = cjMax - (INT)(pjBits - (PBYTE)pv); // Store the handle to bitmap just like a pattern brush, only mark // it as a DIB. HBITMAP hbmDIB; FLONG flCreate = DIB_RGB_COLORS; if (fl != DIB_RGB_COLORS) { flCreate = DIB_PAL_NONE; } hbmDIB = GreCreateDIBitmapReal( (HDC) 0, CBM_INIT | CBM_CREATEDIB, pjBits, (BITMAPINFO *)pv, flCreate, cjMax, cjBits, NULL, 0, NULL, CDBI_INTERNAL, 0, NULL); if (hbmDIB == (HBITMAP) 0) { WARNING("GreCreateDIBPatternBrush failed because GreCreateDIBitmap failed"); return((HBRUSH) 0); } if (b8X8) { SURFREF so((HSURF)hbmDIB); ASSERTGDI(so.bValid(), "ERROR just created and already dead"); SIZEL sizlNew = so.ps->sizl(); if (so.ps->sizl().cx > 8) { sizlNew.cx = 8; } if (so.ps->sizl().cy > 8) { sizlNew.cy = 8; } so.ps->sizl(sizlNew); } // Now if we are creating a DIB_PAL_COLORS DIB brush we need to save the // indices in the palette, so at runtime we can do the right thing. if (fl == DIB_PAL_COLORS) { SURFREF so((HSURF)hbmDIB); ASSERTGDI(so.bValid(), "ERROR GreCreateDIBBrush surface\n"); XEPALOBJ pal(so.ps->ppal()); pal.flPal(PAL_BRUSHHACK); ASSERTGDI(pal.bValid(), "ERROR GreCreateDIBBrush pal.bValid\n"); ASSERTGDI(!pal.bIsPalDefault(), "ERROR GreCreateDIBBrush pal.bIsPal\n"); RtlCopyMemory((PUSHORT) pal.apalColorGet(), pusIndices, cPalEntriesTotal << 1); // Remember how big the color table is pal.cColorTableLength(cPalEntriesTotal); } BRUSHMEMOBJ brmo(hbmDIB, (HBITMAP)pClient, FALSE, fl, BR_IS_DIB, bPen); HBRUSH hbrRet; if (brmo.bValid()) { brmo.vKeepIt(); brmo.iUsage(fl); hbrRet = brmo.hbrush(); } else { bDeleteSurface((HSURF)hbmDIB); hbrRet = (HBRUSH) 0; } return(hbrRet); } /******************************Public*Routine******************************\ * GreMarkUndeletableBrush * * Private API for USER. * * Mark a Brush as undeletable. This must be called before the Brush is ever * passed out to an application. * * History: * 13-Sep-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ VOID GreMarkUndeletableBrush(HBRUSH hbr) { if(hbr == NULL) { WARNING("GreMarkUndeletableBrush called with NULL handle"); } else if(!HmgMarkUndeletable((HOBJ)hbr, BRUSH_TYPE)) { RIP("GreMarkUndeletableBrush failed to mark handle undeletable"); } } /******************************Public*Routine******************************\ * GreMarkDeletableBrush * * Private API for USER. * * This can be called anytime by USER to make the Brush deletable. We need * to check they don't do this on our global objects. * * History: * 13-Sep-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ VOID GreMarkDeletableBrush(HBRUSH hbr) { BRUSHSELOBJ bro(hbr); if (bro.bValid()) { if(!bro.bIsGlobal()) { if (hbr == NULL) { WARNING("GreMarkDeletableBrush called with NULL handle"); } else if (!HmgMarkDeletable((HOBJ)hbr,BRUSH_TYPE)) { RIP("GreMarkDeletableBrush failed to mark handle deletable"); } } } else { WARNING("ERROR User gives Gdi invalid Brush"); } } /******************************Public*Routine******************************\ * GreCreatePen * * API creates a logical pen. * * History: * 08-May-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ HPEN GreCreatePen(int iPenStyle, int ulWidth, COLORREF clrr, HBRUSH hbr) { HPEN hRet = 0; PW32THREAD pthread = W32GetCurrentThread(); ASSERTGDI(!hbr,"GreCreatePen - hbr\n"); switch(iPenStyle) { case PS_NULL: case PS_SOLID: case PS_DASH: case PS_DOT: case PS_DASHDOT: case PS_DASHDOTDOT: case PS_INSIDEFRAME: break; default: SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return((HPEN) 0); } hRet = GreExtCreatePen(iPenStyle, ulWidth, BS_SOLID, clrr, 0, 0, 0, (PULONG) NULL, 0, TRUE, hbr); return (hRet); } /******************************Public*Routine******************************\ * GreExtCreatePen * * API creates an old-style or extended logical pen. * * History: * 23-Jan-1992 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/ HPEN GreExtCreatePen( ULONG flPenStyle, ULONG ulWidth, ULONG iBrushStyle, ULONG ulColor, ULONG_PTR lClientHatch, ULONG_PTR lHatch, ULONG cstyle, PULONG pulStyle, ULONG cjDIB, BOOL bOldStylePen, HBRUSH hbrush) { BOOL bInvalidParm = FALSE; BOOL bDefaultStyle = FALSE; PFLOAT_LONG pstyle = (PFLOAT_LONG) NULL; ULONG iType = flPenStyle & PS_TYPE_MASK; ULONG ulStyle = flPenStyle & PS_STYLE_MASK; ULONG iJoin; ULONG iEndCap; // We take the absoluate value of the integer width, like Win3 does: LONG lWidthPen = ABS((LONG) ulWidth); // Make sure no weird bits are set where none of our fields are: if ((flPenStyle & ~(PS_TYPE_MASK | PS_STYLE_MASK | PS_ENDCAP_MASK | PS_JOIN_MASK)) != 0) { bInvalidParm = TRUE; } // Don't do any more parameter checking for NULL pens: if (ulStyle == PS_NULL) return(STOCKOBJ_NULLPEN); // Do some more parameter checking. switch(iType) { case PS_GEOMETRIC: break; case PS_COSMETIC: if ((iBrushStyle == BS_SOLID) || ((iBrushStyle == BS_HATCHED) && ((lHatch == HS_SOLIDTEXTCLR) || (lHatch == HS_SOLIDBKCLR)))) { break; } default: bInvalidParm = TRUE; } if (lWidthPen != 1 && iType == PS_COSMETIC && !bOldStylePen) { bInvalidParm = TRUE; } switch(flPenStyle & PS_JOIN_MASK) { case PS_JOIN_ROUND: iJoin = JOIN_ROUND; break; case PS_JOIN_BEVEL: iJoin = JOIN_BEVEL; break; case PS_JOIN_MITER: iJoin = JOIN_MITER; break; default: bInvalidParm = TRUE; } switch(flPenStyle & PS_ENDCAP_MASK) { case PS_ENDCAP_ROUND: iEndCap = ENDCAP_ROUND; break; case PS_ENDCAP_FLAT: iEndCap = ENDCAP_BUTT; break; case PS_ENDCAP_SQUARE: iEndCap = ENDCAP_SQUARE; break; default: bInvalidParm = TRUE; } // Zero length array allowed iff not doing a user-supplied style, // and aribtrarily limit the style array size: if ((ulStyle == PS_USERSTYLE && cstyle == 0) || (ulStyle != PS_USERSTYLE && cstyle != 0) || cstyle > STYLE_MAX_COUNT) { bInvalidParm = TRUE; } if (iType == PS_GEOMETRIC) { switch(ulStyle) { case PS_DOT: cstyle = sizeof(gaulGeometricDot) / sizeof(ULONG); pulStyle = gaulGeometricDot; break; case PS_DASH: cstyle = sizeof(gaulGeometricDash) / sizeof(ULONG); pulStyle = gaulGeometricDash; break; case PS_DASHDOT: cstyle = sizeof(gaulGeometricDashDot) / sizeof(ULONG); pulStyle = gaulGeometricDashDot; break; case PS_DASHDOTDOT: cstyle = sizeof(gaulGeometricDashDotDot) / sizeof(ULONG); pulStyle = gaulGeometricDashDotDot; break; case PS_USERSTYLE: case PS_SOLID: break; case PS_INSIDEFRAME: break; case PS_ALTERNATE: default: bInvalidParm = TRUE; } } else { switch(ulStyle) { case PS_DOT: cstyle = sizeof(galeCosmeticDot) / sizeof(LONG_FLOAT); pstyle = &galeCosmeticDot[0].el; bDefaultStyle = TRUE; break; case PS_DASH: cstyle = sizeof(galeCosmeticDash) / sizeof(LONG_FLOAT); pstyle = &galeCosmeticDash[0].el; bDefaultStyle = TRUE; break; case PS_DASHDOT: cstyle = sizeof(galeCosmeticDashDot) / sizeof(LONG_FLOAT); pstyle = &galeCosmeticDashDot[0].el; bDefaultStyle = TRUE; break; case PS_DASHDOTDOT: cstyle = sizeof(galeCosmeticDashDotDot) / sizeof(LONG_FLOAT); pstyle = &galeCosmeticDashDotDot[0].el; bDefaultStyle = TRUE; break; case PS_USERSTYLE: case PS_SOLID: break; case PS_ALTERNATE: break; case PS_INSIDEFRAME: // Don't allow PS_INSIDEFRAME with new style cosmetic pens: if (!bOldStylePen) bInvalidParm = TRUE; break; default: bInvalidParm = TRUE; } } if (bInvalidParm) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return((HPEN) 0); } if (cstyle > 0 && pstyle == (PFLOAT_LONG) NULL) { pstyle = (PFLOAT_LONG) PALLOCNOZ(cstyle * sizeof(FLOAT_LONG),'ytsG'); if (pstyle == (PFLOAT_LONG) NULL) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return((HPEN) 0); } PFLOAT_LONG ple = pstyle; PFLOAT_LONG pleEnd = ple + cstyle; if (iType == PS_COSMETIC || bOldStylePen) { // Handle cosmetic styles: LONG lMin = 1; LONG lMax = 1; LONG lSum = 0; while (ple < pleEnd) { ple->l = (LONG) *pulStyle; lMin = MIN(lMin, ple->l); lMax = MAX(lMax, ple->l); lSum += ple->l; pulStyle++; ple++; } if (lMin <= 0 || lMax > STYLE_MAX_VALUE || lSum > STYLE_MAX_VALUE) bInvalidParm = TRUE; } else { // Handle geometric styles: LONG lSum = 0; LONG lMin = 0; while (ple < pleEnd) { LONG lLength = (LONG) *pulStyle; // Default styles are based on multiples of the pen width: if (ulStyle != PS_USERSTYLE) { // For round and square caps, shorten dashes and lengthen // the gaps: if (iEndCap != ENDCAP_BUTT) lLength += ((ple - pstyle) & 1) ? 1 : -1; // Don't really care about overflow on this multiplication: lLength *= lWidthPen; } lMin = MIN(lMin, lLength); lSum += lLength; EFLOATEXT efLength(lLength); efLength.vEfToF(ple->e); pulStyle++; ple++; } if (lMin < 0 || lSum <= 0) bInvalidParm = TRUE; } if (bInvalidParm) { // At least one entry in the style array has to be non-zero: VFREEMEM(pstyle); SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return((HPEN) 0); } } HBRUSH hbr = 0; switch(iBrushStyle) { case BS_HOLLOW: if (pstyle != (PFLOAT_LONG) NULL && !bDefaultStyle) VFREEMEM(pstyle); return(STOCKOBJ_NULLPEN); case BS_SOLID: hbr = hCreateSolidBrushInternal(ulColor, TRUE, hbrush, (lWidthPen == 0) && (ulStyle == PS_SOLID)); break; case BS_HATCHED: hbr = hCreateHatchBrushInternal((ULONG) lHatch, ulColor, TRUE); break; case BS_PATTERN: hbr = GreCreatePatternBrushInternal((HBITMAP) lHatch, TRUE,FALSE); break; case BS_DIBPATTERNPT: hbr = GreCreateDIBBrush((PVOID) lHatch, ulColor, (UINT) cjDIB, FALSE, TRUE, (PVOID)lClientHatch); break; case BS_DIBPATTERN: RIP("BS_DIBPATTERN not supported in server"); default: SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); } if (hbr == (HBRUSH) 0) { if (pstyle != (PFLOAT_LONG) NULL && !bDefaultStyle) VFREEMEM(pstyle); return((HPEN) 0); } BRUSHSELOBJ bso(hbr); // we had better validate this since it is just a handle, it could already // have been deleted. if (!bso.bValid()) { WARNING("Created invalid pen\n"); if (pstyle != (PFLOAT_LONG) NULL && !bDefaultStyle) VFREEMEM(pstyle); return((HPEN)0); } bso.vSetPen(); bso.flStylePen(flPenStyle); bso.iEndCap(iEndCap); bso.iJoin(iJoin); bso.pstyle(pstyle); bso.cstyle(cstyle); bso.lWidthPen(lWidthPen); if (bDefaultStyle) bso.vSetDefaultStyle(); bso.lBrushStyle (iBrushStyle); bso.lHatch (lClientHatch); if (iType == PS_GEOMETRIC || bOldStylePen) { // Geometric line widths are FLOATs in the LINEATTRS structure, so // we have to keep a FLOAT version of its width around too: EFLOATEXT efWidth(lWidthPen); FLOATL l_eWidth; efWidth.vEfToF(l_eWidth); bso.l_eWidthPen(l_eWidth); } // we need to add the pen/extpen bits to handle type for the client HBRUSH hbrPen = (HBRUSH) MODIFY_HMGR_TYPE(hbr,LO_EXTPEN_TYPE); if (bOldStylePen) { bso.vSetOldStylePen(); bso.vDisableDither(); if (ulStyle == PS_INSIDEFRAME) { bso.vEnableDither(); bso.vSetInsideFrame(); } hbrPen = (HBRUSH) MODIFY_HMGR_TYPE(hbr,LO_PEN_TYPE); } else if (iType == PS_COSMETIC) { // For now, cosmetic lines must also be solid colored: bso.vDisableDither(); } else { // We also support inside frame for geometric ExtCreatePen pens: if (ulStyle == PS_INSIDEFRAME) { bso.vSetInsideFrame(); } } // we now set the new pen handle type. This must be done while the pen is locked HmgModifyHandleType((HOBJ)hbrPen); ASSERTGDI(!bInvalidParm, "Invalid parm?"); return((HPEN) hbrPen); } /******************************Public*Routine******************************\ * GreCreatePenIndirect * * API creates a logical pen. * * History: * 08-May-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ HPEN GreCreatePenIndirect(LPLOGPEN lpLogPen) { return(GreCreatePen((int)lpLogPen->lopnStyle, (int)lpLogPen->lopnWidth.x, lpLogPen->lopnColor,0)); } /******************************Public*Routine******************************\ * GreMonoBitmap * * Is the specified bitmap monochromatic? * * History: * 18-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/ BOOL NtGdiMonoBitmap(HBITMAP hbm) { SURFREF SurfBmo((HSURF)hbm); if (!SurfBmo.bValid()) return(FALSE); XEPALOBJ pal(SurfBmo.ps->ppal()); return(pal.bIsMonochrome()); } /******************************Public*Routine******************************\ * GreGetObjectBitmapHandle * * Gets the handle of the bitmap associated with this brush * * History: * 09-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/ HBITMAP GreGetObjectBitmapHandle( HBRUSH hbr, UINT *piUsage) { BRUSHSELOBJ ebo(hbr); if (!ebo.bValid()) { return((HBITMAP) 0); } HBITMAP hbm = ebo.hbmPattern(); if (ebo.bPalColors()) { *piUsage = DIB_PAL_COLORS; } else if (ebo.bPalIndices()) { *piUsage = DIB_PAL_INDICES; } else { *piUsage = DIB_RGB_COLORS; } return(hbm); }