1// Copyright 2014 PDFium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7#include <algorithm> 8 9#include "xfa/src/foxitlib.h" 10#include "fde_gedevice.h" 11#include "fde_geobject.h" 12#include "fde_devbasic.h" 13#ifndef _FDEPLUS 14#ifdef _cplusplus 15exten "C" { 16#endif 17 FX_BOOL FDE_GetStockHatchMask(int32_t iHatchStyle, CFX_DIBitmap & hatchMask) { 18 FDE_LPCHATCHDATA pData = FDE_DEVGetHatchData(iHatchStyle); 19 if (!pData) { 20 return FALSE; 21 } 22 hatchMask.Create(pData->iWidth, pData->iHeight, FXDIB_1bppMask); 23 FXSYS_memcpy(hatchMask.GetBuffer(), pData->MaskBits, 24 hatchMask.GetPitch() * pData->iHeight); 25 return TRUE; 26 } 27#ifdef _cplusplus 28} 29#endif 30IFDE_RenderDevice* IFDE_RenderDevice::Create(CFX_DIBitmap* pBitmap, 31 FX_BOOL bRgbByteOrder) { 32 if (pBitmap == NULL) { 33 return NULL; 34 } 35 CFX_FxgeDevice* pDevice = new CFX_FxgeDevice; 36 pDevice->Attach(pBitmap, 0, bRgbByteOrder); 37 return new CFDE_FxgeDevice(pDevice, TRUE); 38} 39IFDE_RenderDevice* IFDE_RenderDevice::Create(CFX_RenderDevice* pDevice) { 40 return pDevice ? new CFDE_FxgeDevice(pDevice, FALSE) : nullptr; 41} 42CFDE_FxgeDevice::CFDE_FxgeDevice(CFX_RenderDevice* pDevice, 43 FX_BOOL bOwnerDevice) 44 : m_pDevice(pDevice), 45 m_bOwnerDevice(bOwnerDevice), 46 m_pCharPos(NULL), 47 m_iCharCount(0) { 48 FXSYS_assert(pDevice != NULL); 49 FX_RECT rt = m_pDevice->GetClipBox(); 50 m_rtClip.Set((FX_FLOAT)rt.left, (FX_FLOAT)rt.top, (FX_FLOAT)rt.Width(), 51 (FX_FLOAT)rt.Height()); 52} 53CFDE_FxgeDevice::~CFDE_FxgeDevice() { 54 FX_Free(m_pCharPos); 55 if (m_bOwnerDevice) 56 delete m_pDevice; 57} 58int32_t CFDE_FxgeDevice::GetWidth() const { 59 return m_pDevice->GetWidth(); 60} 61int32_t CFDE_FxgeDevice::GetHeight() const { 62 return m_pDevice->GetHeight(); 63} 64FDE_HDEVICESTATE CFDE_FxgeDevice::SaveState() { 65 m_pDevice->SaveState(); 66 return NULL; 67} 68void CFDE_FxgeDevice::RestoreState(FDE_HDEVICESTATE hState) { 69 m_pDevice->RestoreState(); 70 const FX_RECT& rt = m_pDevice->GetClipBox(); 71 m_rtClip.Set((FX_FLOAT)rt.left, (FX_FLOAT)rt.top, (FX_FLOAT)rt.Width(), 72 (FX_FLOAT)rt.Height()); 73} 74FX_BOOL CFDE_FxgeDevice::SetClipRect(const CFX_RectF& rtClip) { 75 m_rtClip = rtClip; 76 FX_RECT rt((int32_t)FXSYS_floor(rtClip.left), 77 (int32_t)FXSYS_floor(rtClip.top), 78 (int32_t)FXSYS_ceil(rtClip.right()), 79 (int32_t)FXSYS_ceil(rtClip.bottom())); 80 return m_pDevice->SetClip_Rect(&rt); 81} 82const CFX_RectF& CFDE_FxgeDevice::GetClipRect() { 83 return m_rtClip; 84} 85FX_BOOL CFDE_FxgeDevice::SetClipPath(const IFDE_Path* pClip) { 86 return FALSE; 87} 88IFDE_Path* CFDE_FxgeDevice::GetClipPath() const { 89 return NULL; 90} 91FX_FLOAT CFDE_FxgeDevice::GetDpiX() const { 92 return 96; 93} 94FX_FLOAT CFDE_FxgeDevice::GetDpiY() const { 95 return 96; 96} 97FX_BOOL CFDE_FxgeDevice::DrawImage(CFX_DIBSource* pDib, 98 const CFX_RectF* pSrcRect, 99 const CFX_RectF& dstRect, 100 const CFX_Matrix* pImgMatrix, 101 const CFX_Matrix* pDevMatrix) { 102 FXSYS_assert(pDib != NULL); 103 CFX_RectF srcRect; 104 if (pSrcRect) { 105 srcRect = *pSrcRect; 106 } else { 107 srcRect.Set(0, 0, (FX_FLOAT)pDib->GetWidth(), (FX_FLOAT)pDib->GetHeight()); 108 } 109 if (srcRect.IsEmpty()) { 110 return FALSE; 111 } 112 CFX_Matrix dib2fxdev; 113 if (pImgMatrix) { 114 dib2fxdev = *pImgMatrix; 115 } else { 116 dib2fxdev.SetIdentity(); 117 } 118 dib2fxdev.a = dstRect.width; 119 dib2fxdev.d = -dstRect.height; 120 dib2fxdev.e = dstRect.left; 121 dib2fxdev.f = dstRect.bottom(); 122 if (pDevMatrix) { 123 dib2fxdev.Concat(*pDevMatrix); 124 } 125 void* handle = NULL; 126 m_pDevice->StartDIBits(pDib, 255, 0, (const CFX_Matrix*)&dib2fxdev, 0, 127 handle); 128 while (m_pDevice->ContinueDIBits(handle, NULL)) { 129 } 130 m_pDevice->CancelDIBits(handle); 131 return handle != NULL; 132} 133FX_BOOL CFDE_FxgeDevice::DrawString(IFDE_Brush* pBrush, 134 IFX_Font* pFont, 135 const FXTEXT_CHARPOS* pCharPos, 136 int32_t iCount, 137 FX_FLOAT fFontSize, 138 const CFX_Matrix* pMatrix) { 139 FXSYS_assert(pBrush != NULL && pFont != NULL && pCharPos != NULL && 140 iCount > 0); 141 CFX_FontCache* pCache = CFX_GEModule::Get()->GetFontCache(); 142 CFX_Font* pFxFont = (CFX_Font*)pFont->GetDevFont(); 143 switch (pBrush->GetType()) { 144 case FDE_BRUSHTYPE_Solid: { 145 FX_ARGB argb = ((IFDE_SolidBrush*)pBrush)->GetColor(); 146 if ((pFont->GetFontStyles() & FX_FONTSTYLE_Italic) != 0 && 147 !pFxFont->IsItalic()) { 148 FXTEXT_CHARPOS* pCP = (FXTEXT_CHARPOS*)pCharPos; 149 FX_FLOAT* pAM; 150 for (int32_t i = 0; i < iCount; ++i) { 151 static const FX_FLOAT mc = 0.267949f; 152 pAM = pCP->m_AdjustMatrix; 153 pAM[2] = mc * pAM[0] + pAM[2]; 154 pAM[3] = mc * pAM[1] + pAM[3]; 155 pCP++; 156 } 157 } 158 FXTEXT_CHARPOS* pCP = (FXTEXT_CHARPOS*)pCharPos; 159 IFX_Font* pCurFont = NULL; 160 IFX_Font* pSTFont = NULL; 161 FXTEXT_CHARPOS* pCurCP = NULL; 162 int32_t iCurCount = 0; 163#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_ 164 FX_DWORD dwFontStyle = pFont->GetFontStyles(); 165 CFX_Font FxFont; 166 CFX_SubstFont SubstFxFont; 167 FxFont.SetSubstFont(&SubstFxFont); 168 SubstFxFont.m_Weight = dwFontStyle & FX_FONTSTYLE_Bold ? 700 : 400; 169 SubstFxFont.m_WeightCJK = SubstFxFont.m_Weight; 170 SubstFxFont.m_ItalicAngle = dwFontStyle & FX_FONTSTYLE_Italic ? -12 : 0; 171 SubstFxFont.m_bItlicCJK = !!(dwFontStyle & FX_FONTSTYLE_Italic); 172#endif 173 for (int32_t i = 0; i < iCount; ++i) { 174 pSTFont = pFont->GetSubstFont((int32_t)pCP->m_GlyphIndex); 175 pCP->m_GlyphIndex &= 0x00FFFFFF; 176 pCP->m_bFontStyle = FALSE; 177 if (pCurFont != pSTFont) { 178 if (pCurFont != NULL) { 179 pFxFont = (CFX_Font*)pCurFont->GetDevFont(); 180#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_ 181 FxFont.SetFace(pFxFont->GetFace()); 182 m_pDevice->DrawNormalText(iCurCount, pCurCP, &FxFont, pCache, 183 -fFontSize, (const CFX_Matrix*)pMatrix, 184 argb, FXTEXT_CLEARTYPE); 185#else 186 m_pDevice->DrawNormalText(iCurCount, pCurCP, pFxFont, pCache, 187 -fFontSize, (const CFX_Matrix*)pMatrix, 188 argb, FXTEXT_CLEARTYPE); 189#endif 190 } 191 pCurFont = pSTFont; 192 pCurCP = pCP; 193 iCurCount = 1; 194 } else { 195 iCurCount++; 196 } 197 pCP++; 198 } 199 if (pCurFont != NULL && iCurCount) { 200 pFxFont = (CFX_Font*)pCurFont->GetDevFont(); 201#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_ 202 FxFont.SetFace(pFxFont->GetFace()); 203 FX_BOOL bRet = m_pDevice->DrawNormalText( 204 iCurCount, pCurCP, &FxFont, pCache, -fFontSize, 205 (const CFX_Matrix*)pMatrix, argb, FXTEXT_CLEARTYPE); 206 FxFont.SetSubstFont(nullptr); 207 FxFont.SetFace(nullptr); 208 return bRet; 209#else 210 return m_pDevice->DrawNormalText(iCurCount, pCurCP, pFxFont, pCache, 211 -fFontSize, (const CFX_Matrix*)pMatrix, 212 argb, FXTEXT_CLEARTYPE); 213#endif 214 } 215#if _FXM_PLATFORM_ != _FXM_PLATFORM_WINDOWS_ 216 FxFont.SetSubstFont(nullptr); 217 FxFont.SetFace(nullptr); 218#endif 219 return TRUE; 220 } break; 221 default: 222 return FALSE; 223 } 224} 225FX_BOOL CFDE_FxgeDevice::DrawBezier(IFDE_Pen* pPen, 226 FX_FLOAT fPenWidth, 227 const CFX_PointF& pt1, 228 const CFX_PointF& pt2, 229 const CFX_PointF& pt3, 230 const CFX_PointF& pt4, 231 const CFX_Matrix* pMatrix) { 232 CFX_PointsF points; 233 points.Add(pt1); 234 points.Add(pt2); 235 points.Add(pt3); 236 points.Add(pt4); 237 CFDE_Path path; 238 path.AddBezier(points); 239 return DrawPath(pPen, fPenWidth, &path, pMatrix); 240} 241FX_BOOL CFDE_FxgeDevice::DrawCurve(IFDE_Pen* pPen, 242 FX_FLOAT fPenWidth, 243 const CFX_PointsF& points, 244 FX_BOOL bClosed, 245 FX_FLOAT fTension, 246 const CFX_Matrix* pMatrix) { 247 CFDE_Path path; 248 path.AddCurve(points, bClosed, fTension); 249 return DrawPath(pPen, fPenWidth, &path, pMatrix); 250} 251FX_BOOL CFDE_FxgeDevice::DrawEllipse(IFDE_Pen* pPen, 252 FX_FLOAT fPenWidth, 253 const CFX_RectF& rect, 254 const CFX_Matrix* pMatrix) { 255 CFDE_Path path; 256 path.AddEllipse(rect); 257 return DrawPath(pPen, fPenWidth, &path, pMatrix); 258} 259FX_BOOL CFDE_FxgeDevice::DrawLines(IFDE_Pen* pPen, 260 FX_FLOAT fPenWidth, 261 const CFX_PointsF& points, 262 const CFX_Matrix* pMatrix) { 263 CFDE_Path path; 264 path.AddLines(points); 265 return DrawPath(pPen, fPenWidth, &path, pMatrix); 266} 267FX_BOOL CFDE_FxgeDevice::DrawLine(IFDE_Pen* pPen, 268 FX_FLOAT fPenWidth, 269 const CFX_PointF& pt1, 270 const CFX_PointF& pt2, 271 const CFX_Matrix* pMatrix) { 272 CFDE_Path path; 273 path.AddLine(pt1, pt2); 274 return DrawPath(pPen, fPenWidth, &path, pMatrix); 275} 276FX_BOOL CFDE_FxgeDevice::DrawPath(IFDE_Pen* pPen, 277 FX_FLOAT fPenWidth, 278 const IFDE_Path* pPath, 279 const CFX_Matrix* pMatrix) { 280 CFDE_Path* pGePath = (CFDE_Path*)pPath; 281 if (pGePath == NULL) { 282 return FALSE; 283 } 284 CFX_GraphStateData graphState; 285 if (!CreatePen(pPen, fPenWidth, graphState)) { 286 return FALSE; 287 } 288 return m_pDevice->DrawPath(&pGePath->m_Path, (const CFX_Matrix*)pMatrix, 289 &graphState, 0, pPen->GetColor(), 0); 290} 291FX_BOOL CFDE_FxgeDevice::DrawPolygon(IFDE_Pen* pPen, 292 FX_FLOAT fPenWidth, 293 const CFX_PointsF& points, 294 const CFX_Matrix* pMatrix) { 295 CFDE_Path path; 296 path.AddPolygon(points); 297 return DrawPath(pPen, fPenWidth, &path, pMatrix); 298} 299FX_BOOL CFDE_FxgeDevice::DrawRectangle(IFDE_Pen* pPen, 300 FX_FLOAT fPenWidth, 301 const CFX_RectF& rect, 302 const CFX_Matrix* pMatrix) { 303 CFDE_Path path; 304 path.AddRectangle(rect); 305 return DrawPath(pPen, fPenWidth, &path, pMatrix); 306} 307FX_BOOL CFDE_FxgeDevice::FillClosedCurve(IFDE_Brush* pBrush, 308 const CFX_PointsF& points, 309 FX_FLOAT fTension, 310 const CFX_Matrix* pMatrix) { 311 CFDE_Path path; 312 path.AddCurve(points, TRUE, fTension); 313 return FillPath(pBrush, &path, pMatrix); 314} 315FX_BOOL CFDE_FxgeDevice::FillEllipse(IFDE_Brush* pBrush, 316 const CFX_RectF& rect, 317 const CFX_Matrix* pMatrix) { 318 CFDE_Path path; 319 path.AddEllipse(rect); 320 return FillPath(pBrush, &path, pMatrix); 321} 322FX_BOOL CFDE_FxgeDevice::FillPolygon(IFDE_Brush* pBrush, 323 const CFX_PointsF& points, 324 const CFX_Matrix* pMatrix) { 325 CFDE_Path path; 326 path.AddPolygon(points); 327 return FillPath(pBrush, &path, pMatrix); 328} 329FX_BOOL CFDE_FxgeDevice::FillRectangle(IFDE_Brush* pBrush, 330 const CFX_RectF& rect, 331 const CFX_Matrix* pMatrix) { 332 CFDE_Path path; 333 path.AddRectangle(rect); 334 return FillPath(pBrush, &path, pMatrix); 335} 336FX_BOOL CFDE_FxgeDevice::CreatePen(IFDE_Pen* pPen, 337 FX_FLOAT fPenWidth, 338 CFX_GraphStateData& graphState) { 339 if (pPen == NULL) { 340 return FALSE; 341 } 342 graphState.m_LineCap = (CFX_GraphStateData::LineCap)pPen->GetLineCap(); 343 graphState.m_LineJoin = (CFX_GraphStateData::LineJoin)pPen->GetLineJoin(); 344 graphState.m_LineWidth = fPenWidth; 345 graphState.m_MiterLimit = pPen->GetMiterLimit(); 346 graphState.m_DashPhase = pPen->GetDashPhase(); 347 CFX_FloatArray dashArray; 348 switch (pPen->GetDashStyle()) { 349 case FDE_DASHSTYLE_Dash: 350 dashArray.Add(3); 351 dashArray.Add(1); 352 break; 353 case FDE_DASHSTYLE_Dot: 354 dashArray.Add(1); 355 dashArray.Add(1); 356 break; 357 case FDE_DASHSTYLE_DashDot: 358 dashArray.Add(3); 359 dashArray.Add(1); 360 dashArray.Add(1); 361 dashArray.Add(1); 362 break; 363 case FDE_DASHSTYLE_DashDotDot: 364 dashArray.Add(3); 365 dashArray.Add(1); 366 dashArray.Add(1); 367 dashArray.Add(1); 368 dashArray.Add(1); 369 dashArray.Add(1); 370 break; 371 case FDE_DASHSTYLE_Customized: 372 pPen->GetDashArray(dashArray); 373 break; 374 } 375 int32_t iDashCount = dashArray.GetSize(); 376 if (iDashCount > 0) { 377 graphState.SetDashCount(iDashCount); 378 for (int32_t i = 0; i < iDashCount; ++i) { 379 graphState.m_DashArray[i] = dashArray[i] * fPenWidth; 380 } 381 } 382 return TRUE; 383} 384typedef FX_BOOL (CFDE_FxgeDevice::*pfFillPath)(IFDE_Brush* pBrush, 385 const CFX_PathData* pPath, 386 const CFX_Matrix* pMatrix); 387static const pfFillPath gs_FillPath[] = { 388 &CFDE_FxgeDevice::FillSolidPath, &CFDE_FxgeDevice::FillHatchPath, 389 &CFDE_FxgeDevice::FillTexturePath, &CFDE_FxgeDevice::FillLinearGradientPath, 390}; 391FX_BOOL CFDE_FxgeDevice::FillPath(IFDE_Brush* pBrush, 392 const IFDE_Path* pPath, 393 const CFX_Matrix* pMatrix) { 394 CFDE_Path* pGePath = (CFDE_Path*)pPath; 395 if (pGePath == NULL) { 396 return FALSE; 397 } 398 if (pBrush == NULL) { 399 return FALSE; 400 } 401 int32_t iType = pBrush->GetType(); 402 if (iType < 0 || iType > FDE_BRUSHTYPE_MAX) { 403 return FALSE; 404 } 405 return (this->*gs_FillPath[iType])(pBrush, &pGePath->m_Path, pMatrix); 406} 407FX_BOOL CFDE_FxgeDevice::FillSolidPath(IFDE_Brush* pBrush, 408 const CFX_PathData* pPath, 409 const CFX_Matrix* pMatrix) { 410 FXSYS_assert(pPath && pBrush && pBrush->GetType() == FDE_BRUSHTYPE_Solid); 411 IFDE_SolidBrush* pSolidBrush = (IFDE_SolidBrush*)pBrush; 412 return m_pDevice->DrawPath(pPath, (const CFX_Matrix*)pMatrix, NULL, 413 pSolidBrush->GetColor(), 0, FXFILL_WINDING); 414} 415FX_BOOL CFDE_FxgeDevice::FillHatchPath(IFDE_Brush* pBrush, 416 const CFX_PathData* pPath, 417 const CFX_Matrix* pMatrix) { 418 FXSYS_assert(pPath && pBrush && pBrush->GetType() == FDE_BRUSHTYPE_Hatch); 419 IFDE_HatchBrush* pHatchBrush = (IFDE_HatchBrush*)pBrush; 420 int32_t iStyle = pHatchBrush->GetHatchStyle(); 421 if (iStyle < FDE_HATCHSTYLE_Min || iStyle > FDE_HATCHSTYLE_Max) { 422 return FALSE; 423 } 424 CFX_DIBitmap mask; 425 if (!FDE_GetStockHatchMask(iStyle, mask)) { 426 return FALSE; 427 } 428 FX_ARGB dwForeColor = pHatchBrush->GetColor(TRUE); 429 FX_ARGB dwBackColor = pHatchBrush->GetColor(FALSE); 430 CFX_FloatRect rectf = pPath->GetBoundingBox(); 431 if (pMatrix) { 432 rectf.Transform((const CFX_Matrix*)pMatrix); 433 } 434 FX_RECT rect(FXSYS_round(rectf.left), FXSYS_round(rectf.top), 435 FXSYS_round(rectf.right), FXSYS_round(rectf.bottom)); 436 m_pDevice->SaveState(); 437 m_pDevice->StartRendering(); 438 m_pDevice->SetClip_PathFill(pPath, (const CFX_Matrix*)pMatrix, 439 FXFILL_WINDING); 440 m_pDevice->FillRect(&rect, dwBackColor); 441 for (int32_t j = rect.bottom; j < rect.top; j += mask.GetHeight()) 442 for (int32_t i = rect.left; i < rect.right; i += mask.GetWidth()) { 443 m_pDevice->SetBitMask(&mask, i, j, dwForeColor); 444 } 445 m_pDevice->EndRendering(); 446 m_pDevice->RestoreState(); 447 return TRUE; 448} 449FX_BOOL CFDE_FxgeDevice::FillTexturePath(IFDE_Brush* pBrush, 450 const CFX_PathData* pPath, 451 const CFX_Matrix* pMatrix) { 452 FXSYS_assert(pPath && pBrush && pBrush->GetType() == FDE_BRUSHTYPE_Texture); 453 IFDE_TextureBrush* pTextureBrush = (IFDE_TextureBrush*)pBrush; 454 IFDE_Image* pImage = (IFDE_Image*)pTextureBrush->GetImage(); 455 if (pImage == NULL) { 456 return FALSE; 457 } 458 CFX_Size size; 459 size.Set(pImage->GetImageWidth(), pImage->GetImageHeight()); 460 CFX_DIBitmap bmp; 461 bmp.Create(size.x, size.y, FXDIB_Argb); 462 if (!pImage->StartLoadImage(&bmp, 0, 0, size.x, size.y, 0, 0, size.x, 463 size.y)) { 464 return FALSE; 465 } 466 if (pImage->DoLoadImage() < 100) { 467 return FALSE; 468 } 469 pImage->StopLoadImage(); 470 return WrapTexture(pTextureBrush->GetWrapMode(), &bmp, pPath, pMatrix); 471} 472FX_BOOL CFDE_FxgeDevice::WrapTexture(int32_t iWrapMode, 473 const CFX_DIBitmap* pBitmap, 474 const CFX_PathData* pPath, 475 const CFX_Matrix* pMatrix) { 476 CFX_FloatRect rectf = pPath->GetBoundingBox(); 477 if (pMatrix) { 478 rectf.Transform((const CFX_Matrix*)pMatrix); 479 } 480 FX_RECT rect(FXSYS_round(rectf.left), FXSYS_round(rectf.top), 481 FXSYS_round(rectf.right), FXSYS_round(rectf.bottom)); 482 rect.Normalize(); 483 if (rect.IsEmpty()) { 484 return FALSE; 485 } 486 m_pDevice->SaveState(); 487 m_pDevice->StartRendering(); 488 m_pDevice->SetClip_PathFill(pPath, (const CFX_Matrix*)pMatrix, 489 FXFILL_WINDING); 490 switch (iWrapMode) { 491 case FDE_WRAPMODE_Tile: 492 case FDE_WRAPMODE_TileFlipX: 493 case FDE_WRAPMODE_TileFlipY: 494 case FDE_WRAPMODE_TileFlipXY: { 495 FX_BOOL bFlipX = iWrapMode == FDE_WRAPMODE_TileFlipXY || 496 iWrapMode == FDE_WRAPMODE_TileFlipX; 497 FX_BOOL bFlipY = iWrapMode == FDE_WRAPMODE_TileFlipXY || 498 iWrapMode == FDE_WRAPMODE_TileFlipY; 499 const CFX_DIBitmap* pFlip[2][2]; 500 pFlip[0][0] = pBitmap; 501 pFlip[0][1] = bFlipX ? pBitmap->FlipImage(TRUE, FALSE) : pBitmap; 502 pFlip[1][0] = bFlipY ? pBitmap->FlipImage(FALSE, TRUE) : pBitmap; 503 pFlip[1][1] = 504 (bFlipX || bFlipY) ? pBitmap->FlipImage(bFlipX, bFlipY) : pBitmap; 505 int32_t iCounterY = 0; 506 for (int32_t j = rect.top; j < rect.bottom; j += pBitmap->GetHeight()) { 507 int32_t indexY = iCounterY++ % 2; 508 int32_t iCounterX = 0; 509 for (int32_t i = rect.left; i < rect.right; i += pBitmap->GetWidth()) { 510 int32_t indexX = iCounterX++ % 2; 511 m_pDevice->SetDIBits(pFlip[indexY][indexX], i, j); 512 } 513 } 514 if (pFlip[0][1] != pFlip[0][0]) { 515 delete pFlip[0][1]; 516 } 517 if (pFlip[1][0] != pFlip[0][0]) { 518 delete pFlip[1][0]; 519 } 520 if (pFlip[1][1] != pFlip[0][0]) { 521 delete pFlip[1][1]; 522 } 523 } break; 524 case FDE_WRAPMODE_Clamp: { 525 m_pDevice->SetDIBits(pBitmap, rect.left, rect.bottom); 526 } break; 527 } 528 m_pDevice->EndRendering(); 529 m_pDevice->RestoreState(); 530 return TRUE; 531} 532FX_BOOL CFDE_FxgeDevice::FillLinearGradientPath(IFDE_Brush* pBrush, 533 const CFX_PathData* pPath, 534 const CFX_Matrix* pMatrix) { 535 FXSYS_assert(pPath && pBrush && 536 pBrush->GetType() == FDE_BRUSHTYPE_LinearGradient); 537 IFDE_LinearGradientBrush* pLinearBrush = (IFDE_LinearGradientBrush*)pBrush; 538 CFX_PointF pt0, pt1; 539 pLinearBrush->GetLinearPoints(pt0, pt1); 540 CFX_VectorF fDiagonal; 541 fDiagonal.Set(pt0, pt1); 542 FX_FLOAT fTheta = FXSYS_atan2(fDiagonal.y, fDiagonal.x); 543 FX_FLOAT fLength = fDiagonal.Length(); 544 FX_FLOAT fTotalX = fLength / FXSYS_cos(fTheta); 545 FX_FLOAT fTotalY = fLength / FXSYS_cos(FX_PI / 2 - fTheta); 546 FX_FLOAT fSteps = std::max(fTotalX, fTotalY); 547 FX_FLOAT dx = fTotalX / fSteps; 548 FX_FLOAT dy = fTotalY / fSteps; 549 FX_ARGB cr0, cr1; 550 pLinearBrush->GetLinearColors(cr0, cr1); 551 FX_FLOAT a0 = FXARGB_A(cr0); 552 FX_FLOAT r0 = FXARGB_R(cr0); 553 FX_FLOAT g0 = FXARGB_G(cr0); 554 FX_FLOAT b0 = FXARGB_B(cr0); 555 FX_FLOAT da = (FXARGB_A(cr1) - a0) / fSteps; 556 FX_FLOAT dr = (FXARGB_R(cr1) - r0) / fSteps; 557 FX_FLOAT dg = (FXARGB_G(cr1) - g0) / fSteps; 558 FX_FLOAT db = (FXARGB_B(cr1) - b0) / fSteps; 559 CFX_DIBitmap bmp; 560 bmp.Create(FXSYS_round(FXSYS_fabs(fDiagonal.x)), 561 FXSYS_round(FXSYS_fabs(fDiagonal.y)), FXDIB_Argb); 562 CFX_FxgeDevice dev; 563 dev.Attach(&bmp); 564 pt1 = pt0; 565 int32_t iSteps = FXSYS_round(FXSYS_ceil(fSteps)); 566 while (--iSteps >= 0) { 567 cr0 = ArgbEncode(FXSYS_round(a0), FXSYS_round(r0), FXSYS_round(g0), 568 FXSYS_round(b0)); 569 dev.DrawCosmeticLine(pt0.x, pt0.y, pt1.x, pt1.y, cr0); 570 pt1.x += dx; 571 pt0.y += dy; 572 a0 += da; 573 r0 += dr; 574 g0 += dg; 575 b0 += db; 576 } 577 return WrapTexture(pLinearBrush->GetWrapMode(), &bmp, pPath, pMatrix); 578} 579#endif 580