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