| OLD | NEW |
| (Empty) |
| 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 "xfa/fwl/core/cfwl_widgetmgr.h" | |
| 8 | |
| 9 #include <utility> | |
| 10 | |
| 11 #include "third_party/base/ptr_util.h" | |
| 12 #include "xfa/fwl/core/cfwl_app.h" | |
| 13 #include "xfa/fwl/core/cfwl_form.h" | |
| 14 #include "xfa/fwl/core/cfwl_notedriver.h" | |
| 15 #include "xfa/fxfa/app/xfa_fwladapter.h" | |
| 16 #include "xfa/fxfa/xfa_ffapp.h" | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 const int kNeedRepaintHitPoints = 12; | |
| 21 const int kNeedRepaintHitPiece = 3; | |
| 22 | |
| 23 struct FWL_NEEDREPAINTHITDATA { | |
| 24 CFX_PointF hitPoint; | |
| 25 bool bNotNeedRepaint; | |
| 26 bool bNotContainByDirty; | |
| 27 }; | |
| 28 | |
| 29 } // namespace | |
| 30 | |
| 31 bool FWL_UseOffscreen(CFWL_Widget* pWidget) { | |
| 32 #if (_FX_OS_ == _FX_MACOSX_) | |
| 33 return false; | |
| 34 #else | |
| 35 return !!(pWidget->GetStyles() & FWL_WGTSTYLE_Offscreen); | |
| 36 #endif | |
| 37 } | |
| 38 | |
| 39 CFWL_WidgetMgr::CFWL_WidgetMgr(CXFA_FFApp* pAdapterNative) | |
| 40 : m_dwCapability(0), m_pAdapter(pAdapterNative->GetWidgetMgr(this)) { | |
| 41 ASSERT(m_pAdapter); | |
| 42 m_mapWidgetItem[nullptr] = pdfium::MakeUnique<Item>(); | |
| 43 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) | |
| 44 m_rtScreen.Reset(); | |
| 45 #endif | |
| 46 } | |
| 47 | |
| 48 CFWL_WidgetMgr::~CFWL_WidgetMgr() {} | |
| 49 | |
| 50 CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(CFWL_Widget* pWidget) const { | |
| 51 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 52 return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr; | |
| 53 } | |
| 54 | |
| 55 CFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(CFWL_Widget* pWidget) const { | |
| 56 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 57 return pItem && pItem->pOwner ? pItem->pOwner->pWidget : nullptr; | |
| 58 } | |
| 59 | |
| 60 CFWL_Widget* CFWL_WidgetMgr::GetFirstSiblingWidget(CFWL_Widget* pWidget) const { | |
| 61 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 62 if (!pItem) | |
| 63 return nullptr; | |
| 64 | |
| 65 pItem = pItem->pPrevious; | |
| 66 while (pItem && pItem->pPrevious) | |
| 67 pItem = pItem->pPrevious; | |
| 68 return pItem ? pItem->pWidget : nullptr; | |
| 69 } | |
| 70 | |
| 71 CFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(CFWL_Widget* pWidget) const { | |
| 72 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 73 return pItem && pItem->pPrevious ? pItem->pPrevious->pWidget : nullptr; | |
| 74 } | |
| 75 | |
| 76 CFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(CFWL_Widget* pWidget) const { | |
| 77 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 78 return pItem && pItem->pNext ? pItem->pNext->pWidget : nullptr; | |
| 79 } | |
| 80 | |
| 81 CFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(CFWL_Widget* pWidget) const { | |
| 82 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 83 return pItem && pItem->pChild ? pItem->pChild->pWidget : nullptr; | |
| 84 } | |
| 85 | |
| 86 CFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(CFWL_Widget* pWidget) const { | |
| 87 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 88 if (!pItem) | |
| 89 return nullptr; | |
| 90 | |
| 91 pItem = pItem->pChild; | |
| 92 while (pItem && pItem->pNext) | |
| 93 pItem = pItem->pNext; | |
| 94 return pItem ? pItem->pWidget : nullptr; | |
| 95 } | |
| 96 | |
| 97 CFWL_Widget* CFWL_WidgetMgr::GetSystemFormWidget(CFWL_Widget* pWidget) const { | |
| 98 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 99 while (pItem) { | |
| 100 if (IsAbleNative(pItem->pWidget)) | |
| 101 return pItem->pWidget; | |
| 102 pItem = pItem->pParent; | |
| 103 } | |
| 104 return nullptr; | |
| 105 } | |
| 106 | |
| 107 void CFWL_WidgetMgr::AppendWidget(CFWL_Widget* pWidget) { | |
| 108 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 109 if (!pItem) | |
| 110 return; | |
| 111 if (!pItem->pParent) | |
| 112 return; | |
| 113 | |
| 114 Item* pChild = pItem->pParent->pChild; | |
| 115 int32_t i = 0; | |
| 116 while (pChild) { | |
| 117 if (pChild == pItem) { | |
| 118 if (pChild->pPrevious) | |
| 119 pChild->pPrevious->pNext = pChild->pNext; | |
| 120 if (pChild->pNext) | |
| 121 pChild->pNext->pPrevious = pChild->pPrevious; | |
| 122 if (pItem->pParent->pChild == pItem) | |
| 123 pItem->pParent->pChild = pItem->pNext; | |
| 124 | |
| 125 pItem->pNext = nullptr; | |
| 126 pItem->pPrevious = nullptr; | |
| 127 break; | |
| 128 } | |
| 129 if (!pChild->pNext) | |
| 130 break; | |
| 131 | |
| 132 pChild = pChild->pNext; | |
| 133 ++i; | |
| 134 } | |
| 135 | |
| 136 pChild = pItem->pParent->pChild; | |
| 137 if (pChild) { | |
| 138 while (pChild->pNext) | |
| 139 pChild = pChild->pNext; | |
| 140 | |
| 141 pChild->pNext = pItem; | |
| 142 pItem->pPrevious = pChild; | |
| 143 } else { | |
| 144 pItem->pParent->pChild = pItem; | |
| 145 pItem->pPrevious = nullptr; | |
| 146 } | |
| 147 pItem->pNext = nullptr; | |
| 148 } | |
| 149 | |
| 150 void CFWL_WidgetMgr::RepaintWidget(CFWL_Widget* pWidget, | |
| 151 const CFX_RectF* pRect) { | |
| 152 if (!m_pAdapter) | |
| 153 return; | |
| 154 | |
| 155 CFWL_Widget* pNative = pWidget; | |
| 156 CFX_RectF rect(*pRect); | |
| 157 if (IsFormDisabled()) { | |
| 158 CFWL_Widget* pOuter = pWidget->GetOuter(); | |
| 159 while (pOuter) { | |
| 160 CFX_RectF rtTemp = pNative->GetWidgetRect(); | |
| 161 rect.left += rtTemp.left; | |
| 162 rect.top += rtTemp.top; | |
| 163 pNative = pOuter; | |
| 164 pOuter = pOuter->GetOuter(); | |
| 165 } | |
| 166 } else if (!IsAbleNative(pWidget)) { | |
| 167 pNative = GetSystemFormWidget(pWidget); | |
| 168 if (!pNative) | |
| 169 return; | |
| 170 | |
| 171 pWidget->TransformTo(pNative, rect.left, rect.top); | |
| 172 } | |
| 173 AddRedrawCounts(pNative); | |
| 174 m_pAdapter->RepaintWidget(pNative, &rect); | |
| 175 } | |
| 176 | |
| 177 void CFWL_WidgetMgr::InsertWidget(CFWL_Widget* pParent, CFWL_Widget* pChild) { | |
| 178 Item* pParentItem = GetWidgetMgrItem(pParent); | |
| 179 if (!pParentItem) { | |
| 180 auto item = pdfium::MakeUnique<Item>(pParent); | |
| 181 pParentItem = item.get(); | |
| 182 m_mapWidgetItem[pParent] = std::move(item); | |
| 183 | |
| 184 pParentItem->pParent = GetWidgetMgrItem(nullptr); | |
| 185 AppendWidget(pParent); | |
| 186 } | |
| 187 | |
| 188 Item* pItem = GetWidgetMgrItem(pChild); | |
| 189 if (!pItem) { | |
| 190 auto item = pdfium::MakeUnique<Item>(pChild); | |
| 191 pItem = item.get(); | |
| 192 m_mapWidgetItem[pChild] = std::move(item); | |
| 193 } | |
| 194 if (pItem->pParent && pItem->pParent != pParentItem) { | |
| 195 if (pItem->pPrevious) | |
| 196 pItem->pPrevious->pNext = pItem->pNext; | |
| 197 if (pItem->pNext) | |
| 198 pItem->pNext->pPrevious = pItem->pPrevious; | |
| 199 if (pItem->pParent->pChild == pItem) | |
| 200 pItem->pParent->pChild = pItem->pNext; | |
| 201 } | |
| 202 pItem->pParent = pParentItem; | |
| 203 AppendWidget(pChild); | |
| 204 } | |
| 205 | |
| 206 void CFWL_WidgetMgr::RemoveWidget(CFWL_Widget* pWidget) { | |
| 207 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 208 if (!pItem) | |
| 209 return; | |
| 210 if (pItem->pPrevious) | |
| 211 pItem->pPrevious->pNext = pItem->pNext; | |
| 212 if (pItem->pNext) | |
| 213 pItem->pNext->pPrevious = pItem->pPrevious; | |
| 214 if (pItem->pParent && pItem->pParent->pChild == pItem) | |
| 215 pItem->pParent->pChild = pItem->pNext; | |
| 216 | |
| 217 Item* pChild = pItem->pChild; | |
| 218 while (pChild) { | |
| 219 Item* pNext = pChild->pNext; | |
| 220 RemoveWidget(pChild->pWidget); | |
| 221 pChild = pNext; | |
| 222 } | |
| 223 m_mapWidgetItem.erase(pWidget); | |
| 224 } | |
| 225 | |
| 226 void CFWL_WidgetMgr::SetOwner(CFWL_Widget* pOwner, CFWL_Widget* pOwned) { | |
| 227 Item* pParentItem = GetWidgetMgrItem(pOwner); | |
| 228 if (!pParentItem) { | |
| 229 auto item = pdfium::MakeUnique<Item>(pOwner); | |
| 230 pParentItem = item.get(); | |
| 231 m_mapWidgetItem[pOwner] = std::move(item); | |
| 232 | |
| 233 pParentItem->pParent = GetWidgetMgrItem(nullptr); | |
| 234 AppendWidget(pOwner); | |
| 235 } | |
| 236 | |
| 237 Item* pItem = GetWidgetMgrItem(pOwned); | |
| 238 if (!pItem) { | |
| 239 auto item = pdfium::MakeUnique<Item>(pOwned); | |
| 240 pItem = item.get(); | |
| 241 m_mapWidgetItem[pOwned] = std::move(item); | |
| 242 } | |
| 243 pItem->pOwner = pParentItem; | |
| 244 } | |
| 245 void CFWL_WidgetMgr::SetParent(CFWL_Widget* pParent, CFWL_Widget* pChild) { | |
| 246 Item* pParentItem = GetWidgetMgrItem(pParent); | |
| 247 Item* pItem = GetWidgetMgrItem(pChild); | |
| 248 if (!pItem) | |
| 249 return; | |
| 250 if (pItem->pParent && pItem->pParent != pParentItem) { | |
| 251 if (pItem->pPrevious) | |
| 252 pItem->pPrevious->pNext = pItem->pNext; | |
| 253 if (pItem->pNext) | |
| 254 pItem->pNext->pPrevious = pItem->pPrevious; | |
| 255 if (pItem->pParent->pChild == pItem) | |
| 256 pItem->pParent->pChild = pItem->pNext; | |
| 257 | |
| 258 pItem->pNext = nullptr; | |
| 259 pItem->pPrevious = nullptr; | |
| 260 } | |
| 261 pItem->pParent = pParentItem; | |
| 262 AppendWidget(pChild); | |
| 263 } | |
| 264 | |
| 265 void CFWL_WidgetMgr::SetWidgetRect_Native(CFWL_Widget* pWidget, | |
| 266 const CFX_RectF& rect) { | |
| 267 if (!FWL_UseOffscreen(pWidget)) | |
| 268 return; | |
| 269 | |
| 270 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 271 pItem->iRedrawCounter++; | |
| 272 if (pItem->pOffscreen) { | |
| 273 CFX_RenderDevice* pDevice = pItem->pOffscreen->GetRenderDevice(); | |
| 274 if (pDevice && pDevice->GetBitmap()) { | |
| 275 CFX_DIBitmap* pBitmap = pDevice->GetBitmap(); | |
| 276 if (pBitmap->GetWidth() - rect.width > 1 || | |
| 277 pBitmap->GetHeight() - rect.height > 1) { | |
| 278 pItem->pOffscreen.reset(); | |
| 279 } | |
| 280 } | |
| 281 } | |
| 282 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) | |
| 283 pItem->bOutsideChanged = !m_rtScreen.Contains(rect); | |
| 284 #endif | |
| 285 } | |
| 286 | |
| 287 CFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(CFWL_Widget* parent, | |
| 288 FX_FLOAT x, | |
| 289 FX_FLOAT y) { | |
| 290 if (!parent) | |
| 291 return nullptr; | |
| 292 | |
| 293 FX_FLOAT x1; | |
| 294 FX_FLOAT y1; | |
| 295 CFWL_Widget* child = GetLastChildWidget(parent); | |
| 296 while (child) { | |
| 297 if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) { | |
| 298 x1 = x; | |
| 299 y1 = y; | |
| 300 CFX_Matrix matrixOnParent; | |
| 301 child->GetMatrix(matrixOnParent, false); | |
| 302 CFX_Matrix m; | |
| 303 m.SetIdentity(); | |
| 304 m.SetReverse(matrixOnParent); | |
| 305 m.TransformPoint(x1, y1); | |
| 306 CFX_RectF bounds = child->GetWidgetRect(); | |
| 307 if (bounds.Contains(x1, y1)) { | |
| 308 x1 -= bounds.left; | |
| 309 y1 -= bounds.top; | |
| 310 return GetWidgetAtPoint(child, x1, y1); | |
| 311 } | |
| 312 } | |
| 313 child = GetPriorSiblingWidget(child); | |
| 314 } | |
| 315 return parent; | |
| 316 } | |
| 317 | |
| 318 void CFWL_WidgetMgr::NotifySizeChanged(CFWL_Widget* pForm, | |
| 319 FX_FLOAT fx, | |
| 320 FX_FLOAT fy) { | |
| 321 if (FWL_UseOffscreen(pForm)) | |
| 322 GetWidgetMgrItem(pForm)->pOffscreen.reset(); | |
| 323 } | |
| 324 | |
| 325 CFWL_Widget* CFWL_WidgetMgr::NextTab(CFWL_Widget* parent, | |
| 326 CFWL_Widget* focus, | |
| 327 bool& bFind) { | |
| 328 CFWL_WidgetMgr* pMgr = parent->GetOwnerApp()->GetWidgetMgr(); | |
| 329 CFWL_Widget* child = pMgr->GetFirstChildWidget(parent); | |
| 330 while (child) { | |
| 331 if (focus == child) | |
| 332 bFind = true; | |
| 333 | |
| 334 if ((child->GetStyles() & FWL_WGTSTYLE_TabStop) && | |
| 335 (!focus || (focus != child && bFind))) { | |
| 336 return child; | |
| 337 } | |
| 338 CFWL_Widget* bRet = NextTab(child, focus, bFind); | |
| 339 if (bRet) | |
| 340 return bRet; | |
| 341 | |
| 342 child = pMgr->GetNextSiblingWidget(child); | |
| 343 } | |
| 344 return nullptr; | |
| 345 } | |
| 346 | |
| 347 int32_t CFWL_WidgetMgr::CountRadioButtonGroup(CFWL_Widget* pFirst) const { | |
| 348 int32_t iRet = 0; | |
| 349 CFWL_Widget* pChild = pFirst; | |
| 350 while (pChild) { | |
| 351 pChild = GetNextSiblingWidget(pChild); | |
| 352 ++iRet; | |
| 353 } | |
| 354 return iRet; | |
| 355 } | |
| 356 | |
| 357 CFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader( | |
| 358 CFWL_Widget* pRadioButton) const { | |
| 359 CFWL_Widget* pNext = pRadioButton; | |
| 360 if (pNext && (pNext->GetStyles() & FWL_WGTSTYLE_Group)) | |
| 361 return pNext; | |
| 362 return nullptr; | |
| 363 } | |
| 364 | |
| 365 void CFWL_WidgetMgr::GetSameGroupRadioButton( | |
| 366 CFWL_Widget* pRadioButton, | |
| 367 CFX_ArrayTemplate<CFWL_Widget*>& group) const { | |
| 368 CFWL_Widget* pFirst = GetFirstSiblingWidget(pRadioButton); | |
| 369 if (!pFirst) | |
| 370 pFirst = pRadioButton; | |
| 371 | |
| 372 int32_t iGroup = CountRadioButtonGroup(pFirst); | |
| 373 if (iGroup < 2) | |
| 374 return; | |
| 375 group.Add(GetRadioButtonGroupHeader(pRadioButton)); | |
| 376 } | |
| 377 | |
| 378 CFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(CFWL_Widget* pParent) const { | |
| 379 if ((pParent->GetClassID() == FWL_Type::PushButton) && | |
| 380 (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { | |
| 381 return pParent; | |
| 382 } | |
| 383 | |
| 384 CFWL_Widget* child = | |
| 385 pParent->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pParent); | |
| 386 while (child) { | |
| 387 if ((child->GetClassID() == FWL_Type::PushButton) && | |
| 388 (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { | |
| 389 return child; | |
| 390 } | |
| 391 if (CFWL_Widget* find = GetDefaultButton(child)) | |
| 392 return find; | |
| 393 | |
| 394 child = child->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(child); | |
| 395 } | |
| 396 return nullptr; | |
| 397 } | |
| 398 | |
| 399 void CFWL_WidgetMgr::AddRedrawCounts(CFWL_Widget* pWidget) { | |
| 400 GetWidgetMgrItem(pWidget)->iRedrawCounter++; | |
| 401 } | |
| 402 | |
| 403 void CFWL_WidgetMgr::ResetRedrawCounts(CFWL_Widget* pWidget) { | |
| 404 GetWidgetMgrItem(pWidget)->iRedrawCounter = 0; | |
| 405 } | |
| 406 | |
| 407 CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrItem( | |
| 408 CFWL_Widget* pWidget) const { | |
| 409 auto it = m_mapWidgetItem.find(pWidget); | |
| 410 return it != m_mapWidgetItem.end() ? static_cast<Item*>(it->second.get()) | |
| 411 : nullptr; | |
| 412 } | |
| 413 | |
| 414 bool CFWL_WidgetMgr::IsAbleNative(CFWL_Widget* pWidget) const { | |
| 415 if (!pWidget) | |
| 416 return false; | |
| 417 if (!pWidget->IsInstance(FX_WSTRC(FWL_CLASS_Form))) | |
| 418 return false; | |
| 419 | |
| 420 uint32_t dwStyles = pWidget->GetStyles(); | |
| 421 return ((dwStyles & FWL_WGTSTYLE_WindowTypeMask) == | |
| 422 FWL_WGTSTYLE_OverLapper) || | |
| 423 (dwStyles & FWL_WGTSTYLE_Popup); | |
| 424 } | |
| 425 | |
| 426 void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget, | |
| 427 FX_FLOAT fMinHeight, | |
| 428 FX_FLOAT fMaxHeight, | |
| 429 const CFX_RectF& rtAnchor, | |
| 430 CFX_RectF& rtPopup) const { | |
| 431 m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor, rtPopup); | |
| 432 } | |
| 433 | |
| 434 void CFWL_WidgetMgr::OnSetCapability(uint32_t dwCapability) { | |
| 435 m_dwCapability = dwCapability; | |
| 436 } | |
| 437 | |
| 438 void CFWL_WidgetMgr::OnProcessMessageToForm(CFWL_Message* pMessage) { | |
| 439 if (!pMessage) | |
| 440 return; | |
| 441 if (!pMessage->m_pDstTarget) | |
| 442 return; | |
| 443 | |
| 444 CFWL_Widget* pDstWidget = pMessage->m_pDstTarget; | |
| 445 const CFWL_App* pApp = pDstWidget->GetOwnerApp(); | |
| 446 if (!pApp) | |
| 447 return; | |
| 448 | |
| 449 CFWL_NoteDriver* pNoteDriver = | |
| 450 static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver()); | |
| 451 if (!pNoteDriver) | |
| 452 return; | |
| 453 | |
| 454 std::unique_ptr<CFWL_Message> pClonedMessage = pMessage->Clone(); | |
| 455 if (IsFormDisabled()) | |
| 456 pNoteDriver->ProcessMessage(pClonedMessage.get()); | |
| 457 else | |
| 458 pNoteDriver->QueueMessage(std::move(pClonedMessage)); | |
| 459 | |
| 460 #if (_FX_OS_ == _FX_MACOSX_) | |
| 461 CFWL_NoteLoop* pTopLoop = pNoteDriver->GetTopLoop(); | |
| 462 if (pTopLoop) | |
| 463 pNoteDriver->UnqueueMessage(pTopLoop); | |
| 464 #endif | |
| 465 } | |
| 466 | |
| 467 void CFWL_WidgetMgr::OnDrawWidget(CFWL_Widget* pWidget, | |
| 468 CFX_Graphics* pGraphics, | |
| 469 const CFX_Matrix* pMatrix) { | |
| 470 if (!pWidget || !pGraphics) | |
| 471 return; | |
| 472 | |
| 473 CFX_Graphics* pTemp = DrawWidgetBefore(pWidget, pGraphics, pMatrix); | |
| 474 CFX_RectF clipCopy = pWidget->GetWidgetRect(); | |
| 475 clipCopy.left = clipCopy.top = 0; | |
| 476 | |
| 477 if (UseOffscreenDirect(pWidget)) { | |
| 478 DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix); | |
| 479 return; | |
| 480 } | |
| 481 CFX_RectF clipBounds; | |
| 482 | |
| 483 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ || \ | |
| 484 _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_ANDROID_ | |
| 485 pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix); | |
| 486 pGraphics->GetClipRect(clipBounds); | |
| 487 clipCopy = clipBounds; | |
| 488 #elif _FX_OS_ == _FX_MACOSX_ | |
| 489 if (IsFormDisabled()) { | |
| 490 pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix); | |
| 491 pGraphics->GetClipRect(clipBounds); | |
| 492 clipCopy = clipBounds; | |
| 493 } else { | |
| 494 clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d); | |
| 495 const_cast<CFX_Matrix*>(pMatrix)->SetIdentity(); // FIXME: const cast. | |
| 496 pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix); | |
| 497 } | |
| 498 #endif // _FX_OS_ == _FX_MACOSX_ | |
| 499 | |
| 500 if (!IsFormDisabled()) { | |
| 501 CFX_RectF rtClient; | |
| 502 pWidget->GetClientRect(rtClient); | |
| 503 clipBounds.Intersect(rtClient); | |
| 504 } | |
| 505 if (!clipBounds.IsEmpty()) | |
| 506 DrawChild(pWidget, clipBounds, pTemp, pMatrix); | |
| 507 | |
| 508 DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix); | |
| 509 ResetRedrawCounts(pWidget); | |
| 510 } | |
| 511 | |
| 512 void CFWL_WidgetMgr::DrawChild(CFWL_Widget* parent, | |
| 513 const CFX_RectF& rtClip, | |
| 514 CFX_Graphics* pGraphics, | |
| 515 const CFX_Matrix* pMatrix) { | |
| 516 if (!parent) | |
| 517 return; | |
| 518 | |
| 519 bool bFormDisable = IsFormDisabled(); | |
| 520 CFWL_Widget* pNextChild = GetFirstChildWidget(parent); | |
| 521 while (pNextChild) { | |
| 522 CFWL_Widget* child = pNextChild; | |
| 523 pNextChild = GetNextSiblingWidget(child); | |
| 524 if (child->GetStates() & FWL_WGTSTATE_Invisible) | |
| 525 continue; | |
| 526 | |
| 527 CFX_RectF rtWidget = child->GetWidgetRect(); | |
| 528 if (rtWidget.IsEmpty()) | |
| 529 continue; | |
| 530 | |
| 531 CFX_Matrix widgetMatrix; | |
| 532 CFX_RectF clipBounds(rtWidget); | |
| 533 if (!bFormDisable) | |
| 534 child->GetMatrix(widgetMatrix, true); | |
| 535 if (pMatrix) | |
| 536 widgetMatrix.Concat(*pMatrix); | |
| 537 | |
| 538 if (!bFormDisable) { | |
| 539 widgetMatrix.TransformPoint(clipBounds.left, clipBounds.top); | |
| 540 clipBounds.Intersect(rtClip); | |
| 541 if (clipBounds.IsEmpty()) | |
| 542 continue; | |
| 543 | |
| 544 pGraphics->SaveGraphState(); | |
| 545 pGraphics->SetClipRect(clipBounds); | |
| 546 } | |
| 547 widgetMatrix.Translate(rtWidget.left, rtWidget.top, true); | |
| 548 | |
| 549 if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate()) { | |
| 550 if (IsFormDisabled() || IsNeedRepaint(child, &widgetMatrix, rtClip)) | |
| 551 pDelegate->OnDrawWidget(pGraphics, &widgetMatrix); | |
| 552 } | |
| 553 if (!bFormDisable) | |
| 554 pGraphics->RestoreGraphState(); | |
| 555 | |
| 556 DrawChild(child, clipBounds, pGraphics, | |
| 557 bFormDisable ? &widgetMatrix : pMatrix); | |
| 558 child = GetNextSiblingWidget(child); | |
| 559 } | |
| 560 } | |
| 561 | |
| 562 CFX_Graphics* CFWL_WidgetMgr::DrawWidgetBefore(CFWL_Widget* pWidget, | |
| 563 CFX_Graphics* pGraphics, | |
| 564 const CFX_Matrix* pMatrix) { | |
| 565 if (!FWL_UseOffscreen(pWidget)) | |
| 566 return pGraphics; | |
| 567 | |
| 568 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 569 if (!pItem->pOffscreen) { | |
| 570 pItem->pOffscreen.reset(new CFX_Graphics); | |
| 571 CFX_RectF rect = pWidget->GetWidgetRect(); | |
| 572 pItem->pOffscreen->Create((int32_t)rect.width, (int32_t)rect.height, | |
| 573 FXDIB_Argb); | |
| 574 } | |
| 575 CFX_RectF rect; | |
| 576 pGraphics->GetClipRect(rect); | |
| 577 pItem->pOffscreen->SetClipRect(rect); | |
| 578 return pItem->pOffscreen.get(); | |
| 579 } | |
| 580 | |
| 581 void CFWL_WidgetMgr::DrawWidgetAfter(CFWL_Widget* pWidget, | |
| 582 CFX_Graphics* pGraphics, | |
| 583 CFX_RectF& rtClip, | |
| 584 const CFX_Matrix* pMatrix) { | |
| 585 if (FWL_UseOffscreen(pWidget)) { | |
| 586 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 587 pGraphics->Transfer(pItem->pOffscreen.get(), rtClip.left, rtClip.top, | |
| 588 rtClip, pMatrix); | |
| 589 #ifdef _WIN32 | |
| 590 pItem->pOffscreen->ClearClip(); | |
| 591 #endif | |
| 592 } | |
| 593 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 594 pItem->iRedrawCounter = 0; | |
| 595 } | |
| 596 | |
| 597 bool CFWL_WidgetMgr::IsNeedRepaint(CFWL_Widget* pWidget, | |
| 598 CFX_Matrix* pMatrix, | |
| 599 const CFX_RectF& rtDirty) { | |
| 600 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 601 if (pItem && pItem->iRedrawCounter > 0) { | |
| 602 pItem->iRedrawCounter = 0; | |
| 603 return true; | |
| 604 } | |
| 605 | |
| 606 CFX_RectF rtWidget = pWidget->GetWidgetRect(); | |
| 607 rtWidget.left = rtWidget.top = 0; | |
| 608 pMatrix->TransformRect(rtWidget); | |
| 609 if (!rtWidget.IntersectWith(rtDirty)) | |
| 610 return false; | |
| 611 | |
| 612 CFWL_Widget* pChild = | |
| 613 pWidget->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pWidget); | |
| 614 if (!pChild) | |
| 615 return true; | |
| 616 | |
| 617 CFX_RectF rtChilds; | |
| 618 rtChilds.Empty(); | |
| 619 bool bChildIntersectWithDirty = false; | |
| 620 bool bOrginPtIntersectWidthChild = false; | |
| 621 bool bOrginPtIntersectWidthDirty = | |
| 622 rtDirty.Contains(rtWidget.left, rtWidget.top); | |
| 623 static FWL_NEEDREPAINTHITDATA hitPoint[kNeedRepaintHitPoints]; | |
| 624 FXSYS_memset(hitPoint, 0, sizeof(hitPoint)); | |
| 625 FX_FLOAT fxPiece = rtWidget.width / kNeedRepaintHitPiece; | |
| 626 FX_FLOAT fyPiece = rtWidget.height / kNeedRepaintHitPiece; | |
| 627 hitPoint[2].hitPoint.x = hitPoint[6].hitPoint.x = rtWidget.left; | |
| 628 hitPoint[0].hitPoint.x = hitPoint[3].hitPoint.x = hitPoint[7].hitPoint.x = | |
| 629 hitPoint[10].hitPoint.x = fxPiece + rtWidget.left; | |
| 630 hitPoint[1].hitPoint.x = hitPoint[4].hitPoint.x = hitPoint[8].hitPoint.x = | |
| 631 hitPoint[11].hitPoint.x = fxPiece * 2 + rtWidget.left; | |
| 632 hitPoint[5].hitPoint.x = hitPoint[9].hitPoint.x = | |
| 633 rtWidget.width + rtWidget.left; | |
| 634 hitPoint[0].hitPoint.y = hitPoint[1].hitPoint.y = rtWidget.top; | |
| 635 hitPoint[2].hitPoint.y = hitPoint[3].hitPoint.y = hitPoint[4].hitPoint.y = | |
| 636 hitPoint[5].hitPoint.y = fyPiece + rtWidget.top; | |
| 637 hitPoint[6].hitPoint.y = hitPoint[7].hitPoint.y = hitPoint[8].hitPoint.y = | |
| 638 hitPoint[9].hitPoint.y = fyPiece * 2 + rtWidget.top; | |
| 639 hitPoint[10].hitPoint.y = hitPoint[11].hitPoint.y = | |
| 640 rtWidget.height + rtWidget.top; | |
| 641 do { | |
| 642 CFX_RectF rect = pChild->GetWidgetRect(); | |
| 643 CFX_RectF r = rect; | |
| 644 r.left += rtWidget.left; | |
| 645 r.top += rtWidget.top; | |
| 646 if (r.IsEmpty()) | |
| 647 continue; | |
| 648 if (r.Contains(rtDirty)) | |
| 649 return false; | |
| 650 if (!bChildIntersectWithDirty && r.IntersectWith(rtDirty)) | |
| 651 bChildIntersectWithDirty = true; | |
| 652 if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) | |
| 653 bOrginPtIntersectWidthChild = rect.Contains(0, 0); | |
| 654 | |
| 655 if (rtChilds.IsEmpty()) | |
| 656 rtChilds = rect; | |
| 657 else if (!(pChild->GetStates() & FWL_WGTSTATE_Invisible)) | |
| 658 rtChilds.Union(rect); | |
| 659 | |
| 660 for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) { | |
| 661 if (hitPoint[i].bNotContainByDirty || hitPoint[i].bNotNeedRepaint) | |
| 662 continue; | |
| 663 if (!rtDirty.Contains(hitPoint[i].hitPoint)) { | |
| 664 hitPoint[i].bNotContainByDirty = true; | |
| 665 continue; | |
| 666 } | |
| 667 if (r.Contains(hitPoint[i].hitPoint)) | |
| 668 hitPoint[i].bNotNeedRepaint = true; | |
| 669 } | |
| 670 pChild = | |
| 671 pChild->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(pChild); | |
| 672 } while (pChild); | |
| 673 | |
| 674 if (!bChildIntersectWithDirty) | |
| 675 return true; | |
| 676 if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild) | |
| 677 return true; | |
| 678 if (rtChilds.IsEmpty()) | |
| 679 return true; | |
| 680 | |
| 681 int32_t repaintPoint = kNeedRepaintHitPoints; | |
| 682 for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) { | |
| 683 if (hitPoint[i].bNotNeedRepaint) | |
| 684 repaintPoint--; | |
| 685 } | |
| 686 if (repaintPoint > 0) | |
| 687 return true; | |
| 688 | |
| 689 pMatrix->TransformRect(rtChilds); | |
| 690 if (rtChilds.Contains(rtDirty) || rtChilds.Contains(rtWidget)) | |
| 691 return false; | |
| 692 return true; | |
| 693 } | |
| 694 | |
| 695 bool CFWL_WidgetMgr::UseOffscreenDirect(CFWL_Widget* pWidget) const { | |
| 696 Item* pItem = GetWidgetMgrItem(pWidget); | |
| 697 if (!FWL_UseOffscreen(pWidget) || !(pItem->pOffscreen)) | |
| 698 return false; | |
| 699 | |
| 700 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) | |
| 701 if (pItem->bOutsideChanged) { | |
| 702 CFX_RectF r = pWidget->GetWidgetRect(); | |
| 703 CFX_RectF temp(m_rtScreen); | |
| 704 temp.Deflate(50, 50); | |
| 705 if (!temp.Contains(r)) | |
| 706 return false; | |
| 707 | |
| 708 pItem->bOutsideChanged = false; | |
| 709 } | |
| 710 #endif | |
| 711 | |
| 712 return pItem->iRedrawCounter == 0; | |
| 713 } | |
| 714 | |
| 715 CFWL_WidgetMgr::Item::Item() : CFWL_WidgetMgr::Item(nullptr) {} | |
| 716 | |
| 717 CFWL_WidgetMgr::Item::Item(CFWL_Widget* widget) | |
| 718 : pParent(nullptr), | |
| 719 pOwner(nullptr), | |
| 720 pChild(nullptr), | |
| 721 pPrevious(nullptr), | |
| 722 pNext(nullptr), | |
| 723 pWidget(widget), | |
| 724 iRedrawCounter(0) | |
| 725 #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) | |
| 726 , | |
| 727 bOutsideChanged(false) | |
| 728 #endif | |
| 729 { | |
| 730 } | |
| 731 | |
| 732 CFWL_WidgetMgr::Item::~Item() {} | |
| OLD | NEW |