\r
/* Bitmap transparency mask */\r
HBITMAP hbmMask;\r
+ HBITMAP hbmXor;\r
COLORREF rgbTrans;\r
\r
/* data */\r
newObject->keepOrigFormat = TRUE;\r
\r
newObject->hbmMask = NULL;\r
+ newObject->hbmXor = NULL;\r
newObject->loadtime_magic = 0xdeadbeef;\r
newObject->loadtime_format = 0;\r
newObject->bIsDirty = FALSE;\r
switch(Obj->desc.picType) {\r
case PICTYPE_BITMAP:\r
DeleteObject(Obj->desc.u.bmp.hbitmap);\r
+ if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);\r
+ if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);\r
break;\r
case PICTYPE_METAFILE:\r
DeleteMetaFile(Obj->desc.u.wmf.hmeta);\r
SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);\r
SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);\r
\r
- hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);\r
-\r
if (This->hbmMask) {\r
HDC hdcMask = CreateCompatibleDC(0);\r
HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);\r
\r
+ hbmpOld = SelectObject(hdcBmp, This->hbmXor);\r
+\r
SetMapMode(hdcMask, MM_ANISOTROPIC);\r
SetWindowOrgEx(hdcMask, 0, 0, NULL);\r
SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);\r
\r
SelectObject(hdcMask, hOldbm);\r
DeleteDC(hdcMask);\r
- } else\r
+ } else {\r
+ hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);\r
StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);\r
+ }\r
\r
SelectObject(hdcBmp, hbmpOld);\r
DeleteDC(hdcBmp);\r
TRACE("(%p)->(%p).\n", This, pdwAttr);\r
*pdwAttr = 0;\r
switch (This->desc.picType) {\r
- case PICTYPE_BITMAP: break; /* not 'truly' scalable, see MSDN. */\r
+ case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */\r
case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;\r
case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;\r
default:FIXME("Unknown pictype %d\n",This->desc.picType);break;\r
HBITMAP hOldbitmap; \r
HBITMAP hOldbitmapmask;\r
\r
- This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);\r
-\r
- hOldbitmap = SelectObject(hdc,This->desc.u.bmp.hbitmap);\r
+ unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;\r
+ HBITMAP hTempMask;\r
+\r
+ This->hbmXor = CreateDIBitmap(\r
+ hdcref,\r
+ &bmi->bmiHeader,\r
+ CBM_INIT,\r
+ bytes,\r
+ bmi,\r
+ DIB_RGB_COLORS\r
+ );\r
+\r
+ bmi->bmiColors[0].rgbRed = 0;\r
+ bmi->bmiColors[0].rgbGreen = 0;\r
+ bmi->bmiColors[0].rgbBlue = 0;\r
+ bmi->bmiColors[1].rgbRed = 255;\r
+ bmi->bmiColors[1].rgbGreen = 255;\r
+ bmi->bmiColors[1].rgbBlue = 255;\r
+\r
+ bmi->bmiHeader.biBitCount = 1;\r
+ bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;\r
+ bmi->bmiHeader.biClrUsed = 2;\r
+\r
+ for (i = 0; i < gif->SHeight; i++) {\r
+ unsigned char * colorPointer = bytes + padding * i;\r
+ unsigned char * monoPointer = bytes + monopadding * i;\r
+ for (j = 0; j < gif->SWidth; j++) {\r
+ unsigned char pixel = colorPointer[j];\r
+ if ((j & 7) == 0) monoPointer[j >> 3] = 0;\r
+ if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));\r
+ }\r
+ }\r
+ hdcref = GetDC(0);\r
+ hTempMask = CreateDIBitmap(\r
+ hdcref,\r
+ &bmi->bmiHeader,\r
+ CBM_INIT,\r
+ bytes,\r
+ bmi,\r
+ DIB_RGB_COLORS\r
+ );\r
+ DeleteDC(hdcref);\r
+\r
+ bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;\r
+ This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);\r
+ hOldbitmap = SelectObject(hdc, hTempMask);\r
hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);\r
- SetBkColor(hdc, This->rgbTrans);\r
+\r
+ SetBkColor(hdc, RGB(255, 255, 255));\r
BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);\r
\r
/* We no longer need the original bitmap, so we apply the first\r
transformation with the mask to speed up the rendering */\r
+ SelectObject(hdc, This->hbmXor);\r
SetBkColor(hdc, RGB(0,0,0));\r
SetTextColor(hdc, RGB(255,255,255));\r
BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, \r
SelectObject(hdcMask, hOldbitmapmask);\r
DeleteDC(hdcMask);\r
DeleteDC(hdc);\r
+ DeleteObject(hTempMask);\r
}\r
\r
DeleteDC(hdcref);\r
case VT_R4: return VarDecFromR4(V_R4(ps), &V_DECIMAL(pd));\r
case VT_R8: return VarDecFromR8(V_R8(ps), &V_DECIMAL(pd));\r
case VT_DATE: return VarDecFromDate(V_DATE(ps), &V_DECIMAL(pd));\r
- case VT_CY: return VarDecFromCy(V_CY(pd), &V_DECIMAL(ps));\r
- case VT_DISPATCH: return VarDecFromDisp(V_DISPATCH(ps), lcid, &V_DECIMAL(ps));\r
+ case VT_CY: return VarDecFromCy(V_CY(ps), &V_DECIMAL(pd));\r
+ case VT_DISPATCH: return VarDecFromDisp(V_DISPATCH(ps), lcid, &V_DECIMAL(pd));\r
case VT_BSTR: return VarDecFromStr(V_BSTR(ps), lcid, dwFlags, &V_DECIMAL(pd));\r
}\r
break;\r
/**********************************************************************\r
* VarMul [OLEAUT32.156]\r
*\r
+ * Multiply two variants.\r
+ *\r
+ * PARAMS\r
+ * left [I] First variant\r
+ * right [I] Second variant\r
+ * result [O] Result variant\r
+ *\r
+ * RETURNS\r
+ * Success: S_OK.\r
+ * Failure: An HRESULT error code indicating the error.\r
+ *\r
+ * NOTES\r
+ * Native VarMul up to and including WinXP dosn't like as input variants\r
+ * I1, UI2, UI4, UI8, INT and UINT. But it can multiply apples with oranges.\r
+ *\r
+ * Native VarMul dosn't check for NULL in/out pointers and crashes. We do the\r
+ * same here.\r
+ *\r
+ * FIXME\r
+ * Overflow checking for R8 (double) overflow. Return DISP_E_OVERFLOW in that\r
+ * case.\r
*/\r
HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result)\r
{\r
- HRESULT rc = E_FAIL;\r
- VARTYPE lvt,rvt,resvt;\r
- VARIANT lv,rv;\r
- BOOL found;\r
+ HRESULT hres;\r
+ VARTYPE lvt, rvt, resvt, tvt;\r
+ VARIANT lv, rv, tv;\r
+ double r8res;\r
+\r
+ /* Variant priority for coercion. Sorted from lowest to highest.\r
+ VT_ERROR shows an invalid input variant type. */\r
+ enum coerceprio { vt_UI1 = 0, vt_I2, vt_I4, vt_I8, vt_CY, vt_R4, vt_R8,\r
+ vt_DECIMAL, vt_NULL, vt_ERROR };\r
+ /* Mapping from priority to variant type. Keep in sync with coerceprio! */\r
+ VARTYPE prio2vt[] = { VT_UI1, VT_I2, VT_I4, VT_I8, VT_CY, VT_R4, VT_R8,\r
+ VT_DECIMAL, VT_NULL, VT_ERROR };\r
+\r
+ /* Mapping for coercion from input variant to priority of result variant. */\r
+ static VARTYPE coerce[] = {\r
+ /* VT_EMPTY, VT_NULL, VT_I2, VT_I4, VT_R4 */\r
+ vt_UI1, vt_NULL, vt_I2, vt_I4, vt_R4,\r
+ /* VT_R8, VT_CY, VT_DATE, VT_BSTR, VT_DISPATCH */\r
+ vt_R8, vt_CY, vt_R8, vt_R8, vt_ERROR,\r
+ /* VT_ERROR, VT_BOOL, VT_VARIANT, VT_UNKNOWN, VT_DECIMAL */\r
+ vt_ERROR, vt_I2, vt_ERROR, vt_ERROR, vt_DECIMAL,\r
+ /* 15, VT_I1, VT_UI1, VT_UI2, VT_UI4 VT_I8 */\r
+ vt_ERROR, vt_ERROR, vt_UI1, vt_ERROR, vt_ERROR, vt_I8\r
+ };\r
\r
TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),\r
- debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);\r
+ debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right),\r
+ result);\r
\r
- VariantInit(&lv);VariantInit(&rv);\r
+ VariantInit(&lv);\r
+ VariantInit(&rv);\r
+ VariantInit(&tv);\r
lvt = V_VT(left)&VT_TYPEMASK;\r
rvt = V_VT(right)&VT_TYPEMASK;\r
- found = FALSE;resvt=VT_VOID;\r
- if (((1<<lvt) | (1<<rvt)) & (VTBIT_R4|VTBIT_R8)) {\r
- found = TRUE;\r
- resvt = VT_R8;\r
- }\r
- if (!found && (((1<<lvt) | (1<<rvt)) & (VTBIT_I1|VTBIT_I2|VTBIT_UI1|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|(1<<VT_INT)|(1<<VT_UINT)))) {\r
- found = TRUE;\r
- resvt = VT_I4;\r
- }\r
- if (!found) {\r
- FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);\r
- return E_FAIL;\r
- }\r
- rc = VariantChangeType(&lv, left, 0, resvt);\r
- if (FAILED(rc)) {\r
- FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);\r
- return rc;\r
+\r
+ /* If we have any flag set (VT_ARRAY, VT_VECTOR, etc.) bail out.\r
+ Same for any input variant type > VT_I8 */\r
+ if (V_VT(left) & ~VT_TYPEMASK || V_VT(right) & ~VT_TYPEMASK ||\r
+ lvt > VT_I8 || rvt > VT_I8) {\r
+ hres = DISP_E_BADVARTYPE;\r
+ goto end;\r
}\r
- rc = VariantChangeType(&rv, right, 0, resvt);\r
- if (FAILED(rc)) {\r
- FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);\r
- return rc;\r
+\r
+ /* Determine the variant type to coerce to. */\r
+ if (coerce[lvt] > coerce[rvt]) {\r
+ resvt = prio2vt[coerce[lvt]];\r
+ tvt = prio2vt[coerce[rvt]];\r
+ } else {\r
+ resvt = prio2vt[coerce[rvt]];\r
+ tvt = prio2vt[coerce[lvt]];\r
}\r
+\r
+ /* Special cases where the result variant type is defined by both\r
+ input variants and not only that with the highest priority */\r
+ if (resvt == VT_R4 && (tvt == VT_CY || tvt == VT_I8 || tvt == VT_I4))\r
+ resvt = VT_R8;\r
+ if (lvt == VT_EMPTY && rvt == VT_EMPTY)\r
+ resvt = VT_I2;\r
+\r
+ /* For overflow detection use the biggest compatible type for the\r
+ multiplication */\r
switch (resvt) {\r
- case VT_R8:\r
- V_VT(result) = resvt;\r
- V_R8(result) = V_R8(&lv) * V_R8(&rv);\r
- rc = S_OK;\r
- break;\r
- case VT_I4:\r
- V_VT(result) = resvt;\r
- V_I4(result) = V_I4(&lv) * V_I4(&rv);\r
- rc = S_OK;\r
- break;\r
+ case VT_ERROR:\r
+ hres = DISP_E_BADVARTYPE;\r
+ goto end;\r
+ case VT_NULL:\r
+ hres = S_OK;\r
+ V_VT(result) = VT_NULL;\r
+ goto end;\r
+ case VT_UI1:\r
+ case VT_I2:\r
+ case VT_I4:\r
+ case VT_I8:\r
+ tvt = VT_I8;\r
+ break;\r
+ case VT_R4:\r
+ tvt = VT_R8;\r
+ break;\r
+ default:\r
+ tvt = resvt;\r
+ }\r
+\r
+ /* Now coerce the variants */\r
+ hres = VariantChangeType(&lv, left, 0, tvt);\r
+ if (FAILED(hres))\r
+ goto end;\r
+ hres = VariantChangeType(&rv, right, 0, tvt);\r
+ if (FAILED(hres))\r
+ goto end;\r
+\r
+ /* Do the math */\r
+ hres = S_OK;\r
+ V_VT(&tv) = tvt;\r
+ V_VT(result) = resvt;\r
+ switch (tvt) {\r
+ case VT_DECIMAL:\r
+ hres = VarDecMul(&V_DECIMAL(&lv), &V_DECIMAL(&rv),\r
+ &V_DECIMAL(result));\r
+ goto end;\r
+ case VT_CY:\r
+ hres = VarCyMul(V_CY(&lv), V_CY(&rv), &V_CY(result));\r
+ goto end;\r
+ case VT_I8:\r
+ /* Overflow detection */\r
+ r8res = (double)V_I8(&lv) * (double)V_I8(&rv);\r
+ if (r8res > (double)I8_MAX || r8res < (double)I8_MIN) {\r
+ V_VT(result) = VT_R8;\r
+ V_R8(result) = r8res;\r
+ goto end;\r
+ } else\r
+ V_I8(&tv) = V_I8(&lv) * V_I8(&rv);\r
+ break;\r
+ case VT_R8:\r
+ /* FIXME: overflow detection */\r
+ V_R8(&tv) = V_R8(&lv) * V_R8(&rv);\r
+ break;\r
+ default:\r
+ ERR("We shouldn't get here! tvt = %d!\n", tvt);\r
+ break;\r
}\r
- TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result),\r
- debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result));\r
- return rc;\r
+ if (rvt != tvt) {\r
+ while ((hres = VariantChangeType(result, &tv, 0, resvt)) != S_OK) {\r
+ /* Overflow! Change to the vartype with the next higher priority */\r
+ resvt = prio2vt[coerce[resvt] + 1];\r
+ }\r
+ } else\r
+ hres = VariantCopy(result, &tv);\r
+\r
+end:\r
+ if (hres != S_OK) {\r
+ V_VT(result) = VT_EMPTY;\r
+ V_I4(result) = 0; /* No V_EMPTY */\r
+ }\r
+ VariantClear(&lv);\r
+ VariantClear(&rv);\r
+ VariantClear(&tv);\r
+ TRACE("returning 0x%8lx (variant type %s)\n", hres, debugstr_VT(result));\r
+ return hres;\r
}\r
\r
/**********************************************************************\r
return DISP_E_TYPEMISMATCH;\r
case VT_DECIMAL:\r
V_VT(result) = VT_EMPTY;\r
- return E_INVALIDARG;\r
+ return DISP_E_OVERFLOW;\r
case VT_ERROR:\r
return DISP_E_TYPEMISMATCH;\r
case VT_RECORD:\r
} else\r
{\r
V_VT(result) = VT_EMPTY;\r
- return E_INVALIDARG;\r
+ return DISP_E_OVERFLOW;\r
}\r
case VT_ERROR:\r
return DISP_E_TYPEMISMATCH;\r