Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

671 lines
21 KiB

  1. //---------------------------------------------------------------------------
  2. // BorderFill.cpp - implements the drawing API for bgtype = BorderFill
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "Render.h"
  6. #include "Utils.h"
  7. #include "gradient.h"
  8. #include "tmutils.h"
  9. #include "rgn.h"
  10. #include "BorderFill.h"
  11. #include "CacheList.h"
  12. #include "gradient.h"
  13. #include "drawhelp.h"
  14. //---------------------------------------------------------------------------
  15. HRESULT CBorderFill::PackProperties(CRenderObj *pRender, BOOL fNoDraw, int iPartId, int iStateId)
  16. {
  17. memset(this, 0, sizeof(CBorderFill)); // allowed because we have no vtable
  18. _eBgType = BT_BORDERFILL;
  19. //---- save off partid, stateid for debugging ----
  20. _iSourcePartId = iPartId;
  21. _iSourceStateId = iStateId;
  22. if (fNoDraw)
  23. {
  24. //---- this is used to fake a bgtype=none object ----
  25. _fNoDraw = TRUE;
  26. }
  27. else
  28. {
  29. //---- get border type ----
  30. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_BORDERTYPE, (int *)&_eBorderType)))
  31. _eBorderType = BT_RECT; // TODO: Make Zero the default when no bordertype is specified.
  32. //---- get border color ----
  33. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_BORDERCOLOR, &_crBorder)))
  34. _crBorder = RGB(0, 0, 0);
  35. //---- get border size ----
  36. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_BORDERSIZE, &_iBorderSize)))
  37. _iBorderSize = 1; // TODO: Make Zero the default when no bordersize is specified.
  38. if (_eBorderType == BT_ROUNDRECT)
  39. {
  40. //---- get round rect width ----
  41. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_ROUNDCORNERWIDTH, &_iRoundCornerWidth)))
  42. _iRoundCornerWidth = 80;
  43. //---- get round rect height ----
  44. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_ROUNDCORNERHEIGHT, &_iRoundCornerHeight)))
  45. _iRoundCornerHeight = 80;
  46. }
  47. //---- get fill type ----
  48. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_FILLTYPE, (int *)&_eFillType)))
  49. _eFillType = FT_SOLID;
  50. if (_eFillType == FT_SOLID)
  51. {
  52. //---- get fill color ----
  53. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_FILLCOLOR, &_crFill)))
  54. _crFill = RGB(255, 255, 255);
  55. }
  56. else if (_eFillType == FT_TILEIMAGE)
  57. {
  58. _iDibOffset = pRender->GetValueIndex(iPartId, iStateId, TMT_DIBDATA);
  59. if (_iDibOffset == -1) // not found
  60. _iDibOffset = 0;
  61. }
  62. else // one of the graident filltypes
  63. {
  64. _iGradientPartCount = 0;
  65. GRADIENTPART gpParts[5]; // max is 5 for now
  66. for (int i=0; i < ARRAYSIZE(gpParts); i++)
  67. {
  68. COLORREF crPart;
  69. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_GRADIENTCOLOR1+i, &crPart)))
  70. break;
  71. int iPartRatio;
  72. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_GRADIENTRATIO1+i, &iPartRatio)))
  73. iPartRatio = 0;
  74. _crGradientColors[_iGradientPartCount] = crPart;
  75. _iGradientRatios[_iGradientPartCount] = iPartRatio;
  76. _iGradientPartCount++;
  77. }
  78. }
  79. //---- ContentMargins ----
  80. if (FAILED(pRender->GetMargins(NULL, iPartId, iStateId, TMT_CONTENTMARGINS, NULL,
  81. &_ContentMargins)))
  82. {
  83. _ContentMargins.cxLeftWidth = _iBorderSize;
  84. _ContentMargins.cxRightWidth = _iBorderSize;
  85. _ContentMargins.cyTopHeight = _iBorderSize;
  86. _ContentMargins.cyBottomHeight = _iBorderSize;
  87. }
  88. }
  89. return S_OK;
  90. }
  91. //---------------------------------------------------------------------------
  92. BOOL CBorderFill::KeyProperty(int iPropId)
  93. {
  94. BOOL fKey = FALSE;
  95. switch (iPropId)
  96. {
  97. case TMT_BGTYPE:
  98. case TMT_BORDERSIZE:
  99. case TMT_ROUNDCORNERWIDTH:
  100. case TMT_ROUNDCORNERHEIGHT:
  101. case TMT_GRADIENTRATIO1:
  102. case TMT_GRADIENTRATIO2:
  103. case TMT_GRADIENTRATIO3:
  104. case TMT_GRADIENTRATIO4:
  105. case TMT_GRADIENTRATIO5:
  106. //case TMT_IMAGEFILE: // borrowed from imagefile
  107. case TMT_CONTENTMARGINS:
  108. case TMT_BORDERCOLOR:
  109. case TMT_FILLCOLOR:
  110. case TMT_GRADIENTCOLOR1:
  111. case TMT_GRADIENTCOLOR2:
  112. case TMT_GRADIENTCOLOR3:
  113. case TMT_GRADIENTCOLOR4:
  114. case TMT_GRADIENTCOLOR5:
  115. case TMT_BORDERTYPE:
  116. case TMT_FILLTYPE:
  117. fKey = TRUE;
  118. break;
  119. }
  120. return fKey;
  121. }
  122. //---------------------------------------------------------------------------
  123. void CBorderFill::DumpProperties(CSimpleFile *pFile, BYTE *pbThemeData, BOOL fFullInfo)
  124. {
  125. if (fFullInfo)
  126. pFile->OutLine(L"Dump of CBorderFill at offset=0x%x", (BYTE *)this - pbThemeData);
  127. else
  128. pFile->OutLine(L"Dump of CBorderFill");
  129. pFile->OutLine(L" _eBgType=%d, _fNoDraw=%d", _eBgType, _fNoDraw);
  130. pFile->OutLine(L" _eBorderType=%d, _iBorderSize=%d, _crBorder=0x%08x",
  131. _eBorderType, _iBorderSize, _crBorder);
  132. pFile->OutLine(L" _iRoundCornerWidth=%d, _iRoundCornerHeight=%d",
  133. _iRoundCornerWidth, _iRoundCornerHeight);
  134. if (fFullInfo)
  135. {
  136. pFile->OutLine(L" _eFillType=%d, _iDibOffset=%d, _crFill=0x%08x",
  137. _eFillType, _iDibOffset, _crFill);
  138. }
  139. else
  140. {
  141. pFile->OutLine(L" _eFillType=%d, _crFill=0x%08x",
  142. _eFillType, _crFill);
  143. }
  144. pFile->OutLine(L" _ContentMargins=%d, %d, %d, %d",
  145. _ContentMargins.cxLeftWidth, _ContentMargins.cxRightWidth,
  146. _ContentMargins.cyTopHeight, _ContentMargins.cyBottomHeight);
  147. pFile->OutLine(L" _iGradientPartCount=%d", _iGradientPartCount);
  148. for (int i=0; i < _iGradientPartCount; i++)
  149. {
  150. pFile->OutLine(L" _crGradientColors[%d]=0x%08x, _iGradientRatios[%d]=%d",
  151. i, _iGradientRatios[i], i, _iGradientRatios[i]);
  152. }
  153. }
  154. //---------------------------------------------------------------------------
  155. HRESULT CBorderFill::DrawComplexBackground(CRenderObj *pRender, HDC hdcOrig,
  156. const RECT *pRect, BOOL fGettingRegion, BOOL fBorder, BOOL fContent,
  157. OPTIONAL const RECT *pClipRect)
  158. {
  159. CSaveClipRegion scrOrig;
  160. HRESULT hr = S_OK;
  161. bool fGradient = false;
  162. int iWidth;
  163. int iHeight;
  164. //---- pen & brush should proceed hdc so auto-delete happens in correct order ----
  165. CAutoGDI<HPEN> hPen;
  166. CAutoGDI<HBRUSH> hBrush;
  167. CAutoDC hdc(hdcOrig);
  168. CMemoryDC memoryDC;
  169. //---- draw border first (along with simple fills) ----
  170. BOOL fHavePath = FALSE;
  171. int width = WIDTH(*pRect);
  172. int height = HEIGHT(*pRect);
  173. if (pClipRect) // use GDI clipping for complex cases
  174. {
  175. //---- get previous clipping region (for restoring at end) ----
  176. hr = scrOrig.Save(hdc);
  177. if (FAILED(hr))
  178. goto exit;
  179. //---- add "pClipRect" to the GDI clipping region ----
  180. int iRetVal = IntersectClipRect(hdc, pClipRect->left, pClipRect->top,
  181. pClipRect->right, pClipRect->bottom);
  182. if (iRetVal == ERROR)
  183. {
  184. hr = MakeErrorLast();
  185. goto exit;
  186. }
  187. }
  188. if ((fBorder) && (_iBorderSize))
  189. {
  190. hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, _iBorderSize, _crBorder);
  191. if (! hPen)
  192. {
  193. hr = MakeErrorLast();
  194. goto exit;
  195. }
  196. }
  197. if (fContent)
  198. {
  199. if (_eFillType == FT_SOLID)
  200. {
  201. hBrush = CreateSolidBrush(_crFill);
  202. if (! hBrush)
  203. {
  204. hr = MakeErrorLast();
  205. goto exit;
  206. }
  207. }
  208. else if (_eFillType == FT_TILEIMAGE)
  209. {
  210. #if 0
  211. HBITMAP hBitmap = NULL;
  212. //---- don't return on error - will default to NULL brush below ----
  213. HRESULT hr = pRender->GetBitmap(hdc, _iImageFileOffset, iPartId, iStateId, &hBitmap);
  214. if (FAILED(hr))
  215. goto exit;
  216. //Log("TileImage: GetBitmap() returns hr=0x%x, hBitmap=0x%x", hr, hBitmap);
  217. hBrush = CreatePatternBrush(hBitmap);
  218. Log(LOG_TM, L"TileImage: CreatePatternBrush() returns hBrush=0x%x, Error=0x%x", hBrush, GetLastError());
  219. pRender->ReturnBitmap(hBitmap);
  220. if (! hBrush)
  221. {
  222. hr = MakeErrorLast();
  223. goto exit;
  224. }
  225. #endif
  226. }
  227. else
  228. fGradient = true;
  229. }
  230. if (fGettingRegion)
  231. fGradient = false;
  232. if (! hBrush) // no brush wanted
  233. hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
  234. if (! hPen) // no pen wanted
  235. hPen = (HPEN)GetStockObject(NULL_PEN);
  236. hdc.SelectPen(hPen);
  237. hdc.SelectBrush(hBrush);
  238. if (_eBorderType == BT_RECT)
  239. {
  240. if (_iBorderSize > 0)
  241. {
  242. //---- no need to create a path for region in this case ----
  243. Rectangle(hdc, pRect->left, pRect->top, pRect->right, pRect->bottom);
  244. }
  245. else
  246. {
  247. FillRect(hdc, pRect, hBrush);
  248. }
  249. }
  250. else if (_eBorderType == BT_ROUNDRECT)
  251. {
  252. int iEllipHeight = (_iRoundCornerHeight*height)/100;
  253. int iEllipWidth = (_iRoundCornerWidth*width)/100;
  254. RoundRect(hdc, pRect->left, pRect->top, pRect->right, pRect->bottom,
  255. iEllipHeight, iEllipWidth);
  256. if (fGradient) // create a path of the border
  257. {
  258. BeginPath(hdc);
  259. RoundRect(hdc, pRect->left, pRect->top, pRect->right, pRect->bottom,
  260. iEllipHeight, iEllipWidth);
  261. EndPath(hdc);
  262. fHavePath = TRUE;
  263. }
  264. }
  265. else // if (_eBorderType == BT_ELLIPSE)
  266. {
  267. Ellipse(hdc, pRect->left, pRect->top, pRect->right, pRect->bottom);
  268. if (fGradient) // create a path of the border
  269. {
  270. BeginPath(hdc);
  271. Ellipse(hdc, pRect->left, pRect->top, pRect->right, pRect->bottom);
  272. EndPath(hdc);
  273. fHavePath = TRUE;
  274. }
  275. }
  276. if (! fGradient) // we're done
  277. goto exit;
  278. //---- draw gradient fill within the border drawn above ----
  279. //---- shrink rect to subtract border ----
  280. RECT rect;
  281. SetRect(&rect, pRect->left, pRect->top, pRect->right, pRect->bottom);
  282. rect.left += _iBorderSize;
  283. rect.top += _iBorderSize;
  284. rect.right -= _iBorderSize;
  285. rect.bottom -= _iBorderSize;
  286. iWidth = WIDTH(rect);
  287. iHeight = HEIGHT(rect);
  288. hr = memoryDC.OpenDC(hdc, iWidth, iHeight);
  289. if (FAILED(hr))
  290. goto exit;
  291. //---- paint our bounding rect into dcBitmap with our gradient ----
  292. RECT rect2;
  293. SetRect(&rect2, 0, 0, iWidth, iHeight);
  294. GRADIENTPART gpParts[5]; // max is 5 for now
  295. //---- get gradient colors & ratios ----
  296. for (int i=0; i < _iGradientPartCount; i++)
  297. {
  298. COLORREF crPart = _crGradientColors[i];
  299. gpParts[i].Color.bRed = RED(crPart);
  300. gpParts[i].Color.bGreen = GREEN(crPart);
  301. gpParts[i].Color.bBlue = BLUE(crPart);
  302. gpParts[i].Color.bAlpha = 255;
  303. gpParts[i].Ratio = (BYTE)_iGradientRatios[i];
  304. };
  305. if (_eFillType == FT_RADIALGRADIENT)
  306. {
  307. PaintGradientRadialRect(memoryDC, rect2, _iGradientPartCount, gpParts);
  308. }
  309. else if (_eFillType == FT_VERTGRADIENT)
  310. {
  311. PaintVertGradient(memoryDC, rect2, _iGradientPartCount, gpParts);
  312. }
  313. else // if (_eFillType == FT_HORZGRADIENT)
  314. {
  315. PaintHorzGradient(memoryDC, rect2, _iGradientPartCount, gpParts);
  316. }
  317. if (fHavePath)
  318. {
  319. CSaveClipRegion scrCurrent;
  320. hr = scrCurrent.Save(hdc); // save current clip region
  321. if (FAILED(hr))
  322. goto exit;
  323. //---- select our shape as the clipping region in normal hdc ----
  324. SelectClipPath(hdc, RGN_AND);
  325. //---- blt our gradient into the shape-clipped rect into the normal hdc ----
  326. BitBlt(hdc, rect.left, rect.top, iWidth, iHeight, memoryDC, 0, 0, SRCCOPY);
  327. scrCurrent.Restore(hdc); // restore current clip region
  328. }
  329. else
  330. {
  331. //---- blt our gradient into the shape-clipped rect into the normal hdc ----
  332. BitBlt(hdc, rect.left, rect.top, iWidth, iHeight, memoryDC, 0, 0, SRCCOPY);
  333. }
  334. exit:
  335. scrOrig.Restore(hdc); // restore clipping region
  336. return hr;
  337. }
  338. //---------------------------------------------------------------------------
  339. HRESULT CBorderFill::DrawBackground(CRenderObj *pRender, HDC hdcOrig,
  340. const RECT *pRect, OPTIONAL const DTBGOPTS *pOptions)
  341. {
  342. HRESULT hr = S_OK;
  343. //---- options ----
  344. DWORD dwOptionFlags = 0;
  345. BOOL fBorder = TRUE;
  346. BOOL fContent = TRUE;
  347. BOOL fGettingRegion = FALSE;
  348. const RECT *pClipRect = NULL;
  349. if (pOptions)
  350. {
  351. dwOptionFlags = pOptions->dwFlags;
  352. if (dwOptionFlags & DTBG_CLIPRECT)
  353. pClipRect = &pOptions->rcClip;
  354. if (dwOptionFlags & DTBG_OMITBORDER)
  355. fBorder = FALSE;
  356. if (dwOptionFlags & DTBG_OMITCONTENT)
  357. fContent = FALSE;
  358. if (dwOptionFlags & DTBG_COMPUTINGREGION)
  359. fGettingRegion = TRUE;
  360. }
  361. //---- optimize for perf-sensitive paths thru here ----
  362. if (_fNoDraw)
  363. {
  364. //---- nothing to do ----
  365. }
  366. else if ((_eFillType == FT_SOLID) && (_eBorderType == BT_RECT)) // solid rectangle
  367. {
  368. if (! _iBorderSize) // no border case
  369. {
  370. if (fContent)
  371. {
  372. //---- clip, if needed ----
  373. RECT rcContent = *pRect;
  374. if (pClipRect)
  375. IntersectRect(&rcContent, &rcContent, pClipRect);
  376. //---- fastest solid rect ----
  377. COLORREF crOld = SetBkColor(hdcOrig, _crFill);
  378. ExtTextOut(hdcOrig, 0, 0, ETO_OPAQUE, &rcContent, NULL, 0, NULL);
  379. //---- restore old color ----
  380. SetBkColor(hdcOrig, crOld);
  381. }
  382. }
  383. else // border case
  384. {
  385. COLORREF crOld = GetBkColor(hdcOrig);
  386. //---- draw clipped borders ----
  387. if (fBorder)
  388. {
  389. RECT rcLine;
  390. SetBkColor(hdcOrig, _crBorder);
  391. //---- draw LEFT line ----
  392. SetRect(&rcLine, pRect->left, pRect->top, pRect->left+_iBorderSize,
  393. pRect->bottom);
  394. if (pClipRect)
  395. IntersectRect(&rcLine, &rcLine, pClipRect);
  396. ExtTextOut(hdcOrig, 0, 0, ETO_OPAQUE, &rcLine, NULL, 0, NULL);
  397. //---- draw RIGHT line ----
  398. SetRect(&rcLine, pRect->right-_iBorderSize, pRect->top, pRect->right,
  399. pRect->bottom);
  400. if (pClipRect)
  401. IntersectRect(&rcLine, &rcLine, pClipRect);
  402. ExtTextOut(hdcOrig, 0, 0, ETO_OPAQUE, &rcLine, NULL, 0, NULL);
  403. //---- draw TOP line ----
  404. SetRect(&rcLine, pRect->left, pRect->top, pRect->right,
  405. pRect->top+_iBorderSize);
  406. if (pClipRect)
  407. IntersectRect(&rcLine, &rcLine, pClipRect);
  408. ExtTextOut(hdcOrig, 0, 0, ETO_OPAQUE, &rcLine, NULL, 0, NULL);
  409. //---- draw BOTTOM line ----
  410. SetRect(&rcLine, pRect->left, pRect->bottom-_iBorderSize, pRect->right,
  411. pRect->bottom);
  412. if (pClipRect)
  413. IntersectRect(&rcLine, &rcLine, pClipRect);
  414. ExtTextOut(hdcOrig, 0, 0, ETO_OPAQUE, &rcLine, NULL, 0, NULL);
  415. }
  416. //---- remove borders from rect to draw content ----
  417. if (fContent)
  418. {
  419. RECT rcContent = *pRect;
  420. rcContent.left += _iBorderSize;
  421. rcContent.right -= _iBorderSize;
  422. rcContent.top += _iBorderSize;
  423. rcContent.bottom -= _iBorderSize;
  424. if (pClipRect)
  425. IntersectRect(&rcContent, &rcContent, pClipRect);
  426. //---- fastest solid rect ----
  427. SetBkColor(hdcOrig, _crFill);
  428. ExtTextOut(hdcOrig, 0, 0, ETO_OPAQUE, &rcContent, NULL, 0, NULL);
  429. }
  430. //---- restore old color ----
  431. SetBkColor(hdcOrig, crOld);
  432. }
  433. }
  434. else // all other cases
  435. {
  436. hr = DrawComplexBackground(pRender, hdcOrig, pRect, fGettingRegion,
  437. fBorder, fContent, pClipRect);
  438. }
  439. return hr;
  440. }
  441. //---------------------------------------------------------------------------
  442. HRESULT CBorderFill::GetBackgroundRegion(CRenderObj *pRender, OPTIONAL HDC hdc,
  443. const RECT *pRect, HRGN *pRegion)
  444. {
  445. HRESULT hr;
  446. //---- see if it even has a transparent part ----
  447. if (! IsBackgroundPartiallyTransparent())
  448. {
  449. //---- return the bounding rect as the region ----
  450. HRGN hrgn = CreateRectRgn(pRect->left, pRect->top,
  451. pRect->right, pRect->bottom);
  452. if (! hrgn)
  453. return MakeErrorLast();
  454. *pRegion = hrgn;
  455. return S_OK;
  456. }
  457. //---- create a memory dc/bitmap to draw info ----
  458. CMemoryDC hdcMemory;
  459. //---- use maximum drawing values as size of DC ----
  460. hr = hdcMemory.OpenDC(NULL, RECTWIDTH(pRect), RECTHEIGHT(pRect));
  461. if (FAILED(hr))
  462. return hr;
  463. BOOL fOK = BeginPath(hdcMemory);
  464. if (! fOK)
  465. return MakeErrorLast();
  466. DTBGOPTS Opts = {sizeof(Opts), DTBG_COMPUTINGREGION};
  467. hr = DrawBackground(pRender, hdcMemory, pRect, &Opts);
  468. if (FAILED(hr))
  469. return hr;
  470. fOK = EndPath(hdcMemory);
  471. if (! fOK)
  472. return MakeErrorLast();
  473. HRGN hrgn = PathToRegion(hdcMemory);
  474. if (! hrgn)
  475. return MakeErrorLast();
  476. *pRegion = hrgn;
  477. return S_OK;
  478. }
  479. //---------------------------------------------------------------------------
  480. BOOL CBorderFill::IsBackgroundPartiallyTransparent()
  481. {
  482. return ((_eBorderType != BT_RECT) || _fNoDraw);
  483. }
  484. //---------------------------------------------------------------------------
  485. HRESULT CBorderFill::HitTestBackground(CRenderObj *pRender, OPTIONAL HDC hdc,
  486. DWORD dwHTFlags, const RECT *pRect, HRGN hrgn, POINT ptTest, OUT WORD *pwHitCode)
  487. {
  488. MARGINS margins;
  489. GetContentMargins(pRender, hdc, &margins);
  490. *pwHitCode = HitTestRect( dwHTFlags, pRect, margins, ptTest );
  491. return S_OK;
  492. }
  493. //---------------------------------------------------------------------------
  494. void CBorderFill::GetContentMargins(CRenderObj *pRender, OPTIONAL HDC hdc, MARGINS *pMargins)
  495. {
  496. *pMargins = _ContentMargins;
  497. //---- adjust for DPI scaling ----
  498. #if 0
  499. int iDcDpi;
  500. if (DpiDiff(hdc, &iDcDpi)))
  501. {
  502. pMargins->cxLeftWidth = DpiScale(pMargins->cxLeftWidth, iDcDpi);
  503. pMargins->cxRightWidth = DpiScale(pMargins->cxRightWidth, iDcDpi);
  504. pMargins->cyTopHeight = DpiScale(pMargins->cyTopHeight, iDcDpi);
  505. pMargins->cyBottomHeight = DpiScale(pMargins->cyBottomHeight, iDcDpi);
  506. }
  507. #endif
  508. }
  509. //---------------------------------------------------------------------------
  510. HRESULT CBorderFill::GetBackgroundContentRect(CRenderObj *pRender, OPTIONAL HDC hdc,
  511. const RECT *pBoundingRect, RECT *pContentRect)
  512. {
  513. MARGINS margins;
  514. GetContentMargins(pRender, hdc, &margins);
  515. pContentRect->left = pBoundingRect->left + margins.cxLeftWidth;
  516. pContentRect->top = pBoundingRect->top + margins.cyTopHeight;
  517. pContentRect->right = pBoundingRect->right - margins.cxRightWidth;
  518. pContentRect->bottom = pBoundingRect->bottom - margins.cyBottomHeight;
  519. return S_OK;
  520. }
  521. //---------------------------------------------------------------------------
  522. HRESULT CBorderFill::GetBackgroundExtent(CRenderObj *pRender, OPTIONAL HDC hdc,
  523. const RECT *pContentRect, RECT *pExtentRect)
  524. {
  525. MARGINS margins;
  526. GetContentMargins(pRender, hdc, &margins);
  527. pExtentRect->left = pContentRect->left - margins.cxLeftWidth;
  528. pExtentRect->top = pContentRect->top-+ margins.cyTopHeight;
  529. pExtentRect->right = pContentRect->right + margins.cxRightWidth;
  530. pExtentRect->bottom = pContentRect->bottom + margins.cyBottomHeight;
  531. return S_OK;
  532. }
  533. //---------------------------------------------------------------------------
  534. HRESULT CBorderFill::GetPartSize(HDC hdc, THEMESIZE eSize, SIZE *psz)
  535. {
  536. HRESULT hr = S_OK;
  537. if (eSize == TS_MIN)
  538. {
  539. psz->cx = max(1, _iBorderSize*2);
  540. psz->cy = max(1, _iBorderSize*2);
  541. }
  542. else if (eSize == TS_TRUE)
  543. {
  544. psz->cx = _iBorderSize*2 + 1;
  545. psz->cy = _iBorderSize*2 + 1;
  546. }
  547. else
  548. {
  549. hr = MakeError32(E_INVALIDARG);
  550. }
  551. return hr;
  552. }
  553. //---------------------------------------------------------------------------