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/fxfa/xfa_ffpageview.h" 8 9 #include <memory> 10 #include <vector> 11 12 #include "third_party/base/ptr_util.h" 13 #include "third_party/base/stl_util.h" 14 #include "xfa/fde/fde_render.h" 15 #include "xfa/fxfa/app/xfa_ffcheckbutton.h" 16 #include "xfa/fxfa/app/xfa_ffchoicelist.h" 17 #include "xfa/fxfa/app/xfa_fffield.h" 18 #include "xfa/fxfa/app/xfa_ffimageedit.h" 19 #include "xfa/fxfa/app/xfa_ffpushbutton.h" 20 #include "xfa/fxfa/app/xfa_fftextedit.h" 21 #include "xfa/fxfa/app/xfa_fwladapter.h" 22 #include "xfa/fxfa/xfa_ffdoc.h" 23 #include "xfa/fxfa/xfa_ffdocview.h" 24 #include "xfa/fxfa/xfa_ffwidget.h" 25 26 namespace { 27 28 CFX_Matrix GetPageMatrix(const CFX_RectF& docPageRect, 29 const CFX_Rect& devicePageRect, 30 int32_t iRotate, 31 uint32_t dwCoordinatesType) { 32 ASSERT(iRotate >= 0 && iRotate <= 3); 33 34 bool bFlipX = (dwCoordinatesType & 0x01) != 0; 35 bool bFlipY = (dwCoordinatesType & 0x02) != 0; 36 CFX_Matrix m((bFlipX ? -1.0f : 1.0f), 0, 0, (bFlipY ? -1.0f : 1.0f), 0, 0); 37 if (iRotate == 0 || iRotate == 2) { 38 m.a *= (FX_FLOAT)devicePageRect.width / docPageRect.width; 39 m.d *= (FX_FLOAT)devicePageRect.height / docPageRect.height; 40 } else { 41 m.a *= (FX_FLOAT)devicePageRect.height / docPageRect.width; 42 m.d *= (FX_FLOAT)devicePageRect.width / docPageRect.height; 43 } 44 m.Rotate(iRotate * 1.57079632675f); 45 switch (iRotate) { 46 case 0: 47 m.e = bFlipX ? (FX_FLOAT)devicePageRect.right() 48 : (FX_FLOAT)devicePageRect.left; 49 m.f = bFlipY ? (FX_FLOAT)devicePageRect.bottom() 50 : (FX_FLOAT)devicePageRect.top; 51 break; 52 case 1: 53 m.e = bFlipY ? (FX_FLOAT)devicePageRect.left 54 : (FX_FLOAT)devicePageRect.right(); 55 m.f = bFlipX ? (FX_FLOAT)devicePageRect.bottom() 56 : (FX_FLOAT)devicePageRect.top; 57 break; 58 case 2: 59 m.e = bFlipX ? (FX_FLOAT)devicePageRect.left 60 : (FX_FLOAT)devicePageRect.right(); 61 m.f = bFlipY ? (FX_FLOAT)devicePageRect.top 62 : (FX_FLOAT)devicePageRect.bottom(); 63 break; 64 case 3: 65 m.e = bFlipY ? (FX_FLOAT)devicePageRect.right() 66 : (FX_FLOAT)devicePageRect.left; 67 m.f = bFlipX ? (FX_FLOAT)devicePageRect.top 68 : (FX_FLOAT)devicePageRect.bottom(); 69 break; 70 default: 71 break; 72 } 73 return m; 74 } 75 76 bool PageWidgetFilter(CXFA_FFWidget* pWidget, 77 uint32_t dwFilter, 78 bool bTraversal, 79 bool bIgnorerelevant) { 80 CXFA_WidgetAcc* pWidgetAcc = pWidget->GetDataAcc(); 81 82 if (!!(dwFilter & XFA_WidgetStatus_Focused) && 83 pWidgetAcc->GetElementType() != XFA_Element::Field) { 84 return false; 85 } 86 87 uint32_t dwStatus = pWidget->GetStatus(); 88 if (bTraversal && (dwStatus & XFA_WidgetStatus_Disabled)) 89 return false; 90 if (bIgnorerelevant) 91 return !!(dwStatus & XFA_WidgetStatus_Visible); 92 93 dwFilter &= (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable | 94 XFA_WidgetStatus_Printable); 95 return (dwFilter & dwStatus) == dwFilter; 96 } 97 98 bool IsLayoutElement(XFA_Element eElement, bool bLayoutContainer) { 99 switch (eElement) { 100 case XFA_Element::Draw: 101 case XFA_Element::Field: 102 case XFA_Element::InstanceManager: 103 return !bLayoutContainer; 104 case XFA_Element::Area: 105 case XFA_Element::Subform: 106 case XFA_Element::ExclGroup: 107 case XFA_Element::SubformSet: 108 case XFA_Element::PageArea: 109 case XFA_Element::Form: 110 return true; 111 default: 112 return false; 113 } 114 } 115 116 } // namespace 117 118 CXFA_FFPageView::CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea) 119 : CXFA_ContainerLayoutItem(pPageArea), m_pDocView(pDocView) {} 120 121 CXFA_FFPageView::~CXFA_FFPageView() {} 122 123 CXFA_FFDocView* CXFA_FFPageView::GetDocView() const { 124 return m_pDocView; 125 } 126 127 CFX_RectF CXFA_FFPageView::GetPageViewRect() const { 128 return CFX_RectF(0, 0, GetPageSize()); 129 } 130 131 CFX_Matrix CXFA_FFPageView::GetDisplayMatrix(const CFX_Rect& rtDisp, 132 int32_t iRotate) const { 133 return GetPageMatrix(CFX_RectF(0, 0, GetPageSize()), rtDisp, iRotate, 0); 134 } 135 136 IXFA_WidgetIterator* CXFA_FFPageView::CreateWidgetIterator( 137 uint32_t dwTraverseWay, 138 uint32_t dwWidgetFilter) { 139 switch (dwTraverseWay) { 140 case XFA_TRAVERSEWAY_Tranvalse: 141 return new CXFA_FFTabOrderPageWidgetIterator(this, dwWidgetFilter); 142 case XFA_TRAVERSEWAY_Form: 143 return new CXFA_FFPageWidgetIterator(this, dwWidgetFilter); 144 } 145 return nullptr; 146 } 147 148 CXFA_FFPageWidgetIterator::CXFA_FFPageWidgetIterator(CXFA_FFPageView* pPageView, 149 uint32_t dwFilter) { 150 m_pPageView = pPageView; 151 m_dwFilter = dwFilter; 152 m_sIterator.Init(pPageView); 153 m_bIgnorerelevant = 154 m_pPageView->GetDocView()->GetDoc()->GetXFADoc()->GetCurVersionMode() < 155 XFA_VERSION_205; 156 } 157 CXFA_FFPageWidgetIterator::~CXFA_FFPageWidgetIterator() {} 158 void CXFA_FFPageWidgetIterator::Reset() { 159 m_sIterator.Reset(); 160 } 161 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToFirst() { 162 m_sIterator.Reset(); 163 for (CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent(); pLayoutItem; 164 pLayoutItem = m_sIterator.MoveToNext()) { 165 if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) { 166 return hWidget; 167 } 168 } 169 return nullptr; 170 } 171 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToLast() { 172 m_sIterator.SetCurrent(nullptr); 173 return MoveToPrevious(); 174 } 175 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToNext() { 176 for (CXFA_LayoutItem* pLayoutItem = m_sIterator.MoveToNext(); pLayoutItem; 177 pLayoutItem = m_sIterator.MoveToNext()) { 178 if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) { 179 return hWidget; 180 } 181 } 182 return nullptr; 183 } 184 CXFA_FFWidget* CXFA_FFPageWidgetIterator::MoveToPrevious() { 185 for (CXFA_LayoutItem* pLayoutItem = m_sIterator.MoveToPrev(); pLayoutItem; 186 pLayoutItem = m_sIterator.MoveToPrev()) { 187 if (CXFA_FFWidget* hWidget = GetWidget(pLayoutItem)) { 188 return hWidget; 189 } 190 } 191 return nullptr; 192 } 193 CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetCurrentWidget() { 194 CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent(); 195 return pLayoutItem ? XFA_GetWidgetFromLayoutItem(pLayoutItem) : nullptr; 196 } 197 bool CXFA_FFPageWidgetIterator::SetCurrentWidget(CXFA_FFWidget* hWidget) { 198 return hWidget && m_sIterator.SetCurrent(hWidget); 199 } 200 CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetWidget( 201 CXFA_LayoutItem* pLayoutItem) { 202 if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) { 203 if (!PageWidgetFilter(pWidget, m_dwFilter, false, m_bIgnorerelevant)) { 204 return nullptr; 205 } 206 if (!pWidget->IsLoaded() && 207 (pWidget->GetStatus() & XFA_WidgetStatus_Visible) != 0) { 208 pWidget->LoadWidget(); 209 } 210 return pWidget; 211 } 212 return nullptr; 213 } 214 215 CXFA_FFTabOrderPageWidgetIterator::CXFA_FFTabOrderPageWidgetIterator( 216 CXFA_FFPageView* pPageView, 217 uint32_t dwFilter) 218 : m_pPageView(pPageView), m_dwFilter(dwFilter), m_iCurWidget(-1) { 219 m_bIgnorerelevant = 220 m_pPageView->GetDocView()->GetDoc()->GetXFADoc()->GetCurVersionMode() < 221 XFA_VERSION_205; 222 Reset(); 223 } 224 225 CXFA_FFTabOrderPageWidgetIterator::~CXFA_FFTabOrderPageWidgetIterator() {} 226 227 void CXFA_FFTabOrderPageWidgetIterator::Reset() { 228 CreateTabOrderWidgetArray(); 229 m_iCurWidget = -1; 230 } 231 232 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToFirst() { 233 for (int32_t i = 0; 234 i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) { 235 if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true, 236 m_bIgnorerelevant)) { 237 m_iCurWidget = i; 238 return m_TabOrderWidgetArray[m_iCurWidget]; 239 } 240 } 241 return nullptr; 242 } 243 244 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToLast() { 245 for (int32_t i = pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) - 1; 246 i >= 0; i--) { 247 if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true, 248 m_bIgnorerelevant)) { 249 m_iCurWidget = i; 250 return m_TabOrderWidgetArray[m_iCurWidget]; 251 } 252 } 253 return nullptr; 254 } 255 256 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToNext() { 257 for (int32_t i = m_iCurWidget + 1; 258 i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) { 259 if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true, 260 m_bIgnorerelevant)) { 261 m_iCurWidget = i; 262 return m_TabOrderWidgetArray[m_iCurWidget]; 263 } 264 } 265 m_iCurWidget = -1; 266 return nullptr; 267 } 268 269 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToPrevious() { 270 for (int32_t i = m_iCurWidget - 1; i >= 0; i--) { 271 if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true, 272 m_bIgnorerelevant)) { 273 m_iCurWidget = i; 274 return m_TabOrderWidgetArray[m_iCurWidget]; 275 } 276 } 277 m_iCurWidget = -1; 278 return nullptr; 279 } 280 281 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetCurrentWidget() { 282 return m_iCurWidget >= 0 ? m_TabOrderWidgetArray[m_iCurWidget] : nullptr; 283 } 284 285 bool CXFA_FFTabOrderPageWidgetIterator::SetCurrentWidget( 286 CXFA_FFWidget* hWidget) { 287 auto it = std::find(m_TabOrderWidgetArray.begin(), 288 m_TabOrderWidgetArray.end(), hWidget); 289 if (it == m_TabOrderWidgetArray.end()) 290 return false; 291 292 m_iCurWidget = it - m_TabOrderWidgetArray.begin(); 293 return true; 294 } 295 296 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetTraverseWidget( 297 CXFA_FFWidget* pWidget) { 298 CXFA_WidgetAcc* pAcc = pWidget->GetDataAcc(); 299 CXFA_Node* pTraversal = pAcc->GetNode()->GetChild(0, XFA_Element::Traversal); 300 if (pTraversal) { 301 CXFA_Node* pTraverse = pTraversal->GetChild(0, XFA_Element::Traverse); 302 if (pTraverse) { 303 CFX_WideString wsTraverseWidgetName; 304 if (pTraverse->GetAttribute(XFA_ATTRIBUTE_Ref, wsTraverseWidgetName)) { 305 return FindWidgetByName(wsTraverseWidgetName, pWidget); 306 } 307 } 308 } 309 return nullptr; 310 } 311 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::FindWidgetByName( 312 const CFX_WideString& wsWidgetName, 313 CXFA_FFWidget* pRefWidget) { 314 return pRefWidget->GetDocView()->GetWidgetByName(wsWidgetName, pRefWidget); 315 } 316 317 void CXFA_FFTabOrderPageWidgetIterator::CreateTabOrderWidgetArray() { 318 m_TabOrderWidgetArray.clear(); 319 320 std::vector<CXFA_FFWidget*> SpaceOrderWidgetArray; 321 CreateSpaceOrderWidgetArray(&SpaceOrderWidgetArray); 322 if (SpaceOrderWidgetArray.empty()) 323 return; 324 325 int32_t nWidgetCount = pdfium::CollectionSize<int32_t>(SpaceOrderWidgetArray); 326 CXFA_FFWidget* hWidget = SpaceOrderWidgetArray[0]; 327 while (pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) < 328 nWidgetCount) { 329 if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) { 330 m_TabOrderWidgetArray.push_back(hWidget); 331 CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc(); 332 if (pWidgetAcc->GetUIType() == XFA_Element::ExclGroup) { 333 auto it = std::find(SpaceOrderWidgetArray.begin(), 334 SpaceOrderWidgetArray.end(), hWidget); 335 int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end() 336 ? it - SpaceOrderWidgetArray.begin() + 1 337 : 0; 338 while (true) { 339 CXFA_FFWidget* pRadio = 340 SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount]; 341 if (pRadio->GetDataAcc()->GetExclGroup() != pWidgetAcc) { 342 break; 343 } 344 if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) { 345 m_TabOrderWidgetArray.push_back(pRadio); 346 } 347 iWidgetIndex++; 348 } 349 } 350 if (CXFA_FFWidget* hTraverseWidget = GetTraverseWidget(hWidget)) { 351 hWidget = hTraverseWidget; 352 continue; 353 } 354 } 355 auto it = std::find(SpaceOrderWidgetArray.begin(), 356 SpaceOrderWidgetArray.end(), hWidget); 357 int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end() 358 ? it - SpaceOrderWidgetArray.begin() + 1 359 : 0; 360 hWidget = SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount]; 361 } 362 } 363 364 static int32_t XFA_TabOrderWidgetComparator(const void* phWidget1, 365 const void* phWidget2) { 366 auto param1 = *static_cast<CXFA_TabParam**>(const_cast<void*>(phWidget1)); 367 auto param2 = *static_cast<CXFA_TabParam**>(const_cast<void*>(phWidget2)); 368 CFX_RectF rt1 = param1->m_pWidget->GetWidgetRect(); 369 CFX_RectF rt2 = param2->m_pWidget->GetWidgetRect(); 370 FX_FLOAT x1 = rt1.left, y1 = rt1.top, x2 = rt2.left, y2 = rt2.top; 371 if (y1 < y2 || (y1 - y2 < XFA_FLOAT_PERCISION && x1 < x2)) 372 return -1; 373 return 1; 374 } 375 376 void CXFA_FFTabOrderPageWidgetIterator::OrderContainer( 377 CXFA_LayoutItemIterator* sIterator, 378 CXFA_LayoutItem* pContainerItem, 379 CXFA_TabParam* pContainer, 380 bool& bCurrentItem, 381 bool& bContentArea, 382 bool bMarsterPage) { 383 CFX_ArrayTemplate<CXFA_TabParam*> tabParams; 384 CXFA_LayoutItem* pSearchItem = sIterator->MoveToNext(); 385 while (pSearchItem) { 386 if (!pSearchItem->IsContentLayoutItem()) { 387 bContentArea = true; 388 pSearchItem = sIterator->MoveToNext(); 389 continue; 390 } 391 if (bMarsterPage && bContentArea) { 392 break; 393 } 394 if (bMarsterPage || bContentArea) { 395 CXFA_FFWidget* hWidget = GetWidget(pSearchItem); 396 if (!hWidget) { 397 pSearchItem = sIterator->MoveToNext(); 398 continue; 399 } 400 if (pContainerItem && (pSearchItem->GetParent() != pContainerItem)) { 401 bCurrentItem = true; 402 break; 403 } 404 CXFA_TabParam* pParam = new CXFA_TabParam; 405 pParam->m_pWidget = hWidget; 406 tabParams.Add(pParam); 407 if (IsLayoutElement(pSearchItem->GetFormNode()->GetElementType(), true)) { 408 OrderContainer(sIterator, pSearchItem, pParam, bCurrentItem, 409 bContentArea, bMarsterPage); 410 } 411 } 412 if (bCurrentItem) { 413 pSearchItem = sIterator->GetCurrent(); 414 bCurrentItem = false; 415 } else { 416 pSearchItem = sIterator->MoveToNext(); 417 } 418 } 419 int32_t iChildren = tabParams.GetSize(); 420 if (iChildren > 1) { 421 FXSYS_qsort(tabParams.GetData(), iChildren, sizeof(void*), 422 XFA_TabOrderWidgetComparator); 423 } 424 for (int32_t iStart = 0; iStart < iChildren; iStart++) { 425 std::unique_ptr<CXFA_TabParam> pParam(tabParams[iStart]); 426 pContainer->m_Children.push_back(pParam->m_pWidget); 427 pContainer->m_Children.insert(pContainer->m_Children.end(), 428 pParam->m_Children.begin(), 429 pParam->m_Children.end()); 430 } 431 tabParams.RemoveAll(); 432 } 433 void CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderWidgetArray( 434 std::vector<CXFA_FFWidget*>* WidgetArray) { 435 CXFA_LayoutItemIterator sIterator; 436 sIterator.Init(m_pPageView); 437 auto pParam = pdfium::MakeUnique<CXFA_TabParam>(); 438 bool bCurrentItem = false; 439 bool bContentArea = false; 440 OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea); 441 WidgetArray->insert(WidgetArray->end(), pParam->m_Children.begin(), 442 pParam->m_Children.end()); 443 444 sIterator.Reset(); 445 bCurrentItem = false; 446 bContentArea = false; 447 pParam->m_Children.clear(); 448 OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea, 449 true); 450 WidgetArray->insert(WidgetArray->end(), pParam->m_Children.begin(), 451 pParam->m_Children.end()); 452 } 453 454 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetWidget( 455 CXFA_LayoutItem* pLayoutItem) { 456 if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) { 457 if (!pWidget->IsLoaded() && 458 (pWidget->GetStatus() & XFA_WidgetStatus_Visible)) { 459 pWidget->LoadWidget(); 460 } 461 return pWidget; 462 } 463 return nullptr; 464 } 465 466 CXFA_TabParam::CXFA_TabParam() : m_pWidget(nullptr) {} 467 468 CXFA_TabParam::~CXFA_TabParam() {} 469