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/src/foxitlib.h" 8 #include "fde_csssyntax.h" 9 #include "fde_cssdatatable.h" 10 #include "fde_cssstylesheet.h" 11 IFDE_CSSStyleSheet* IFDE_CSSStyleSheet::LoadHTMLStandardStyleSheet() { 12 static const FX_WCHAR* s_pStyle = 13 L"html,address,blockquote,body,dd,div,dl,dt,fieldset,form,frame,frameset," 14 L"h1,h2,h3,h4,h5,h6,noframes,ol,p,ul,center,dir,hr,menu,pre{display:" 15 L"block}" 16 L"li{display:list-item}head{display:none}table{display:table}tr{display:" 17 L"table-row}thead{display:table-header-group}tbody{display:table-row-" 18 L"group}tfoot{display:table-footer-group}" 19 L"col{display:table-column}colgroup{display:table-column-group}td,th{" 20 L"display:table-cell}caption{display:table-caption}th{font-weight:bolder;" 21 L"text-align:center}caption{text-align:center}" 22 L"body{margin:0}h1{font-size:2em;margin:.67em " 23 L"0}h2{font-size:1.5em;margin:.75em 0}h3{font-size:1.17em;margin:.83em " 24 L"0}h4,p,blockquote,ul,fieldset,form,ol,dl,dir,menu{margin:1.12em 0}" 25 L"h5{font-size:.83em;margin:1.5em 0}h6{font-size:.75em;margin:1.67em " 26 L"0}h1,h2,h3,h4,h5,h6,b,strong{font-weight:bolder}blockquote{margin-left:" 27 L"40px;margin-right:40px}i,cite,em,var,address{font-style:italic}" 28 L"pre,tt,code,kbd,samp{font-family:monospace}pre{white-space:pre}button," 29 L"textarea,input,select{display:inline-block}big{font-size:1.17em}small," 30 L"sub,sup{font-size:.83em}sub{vertical-align:sub}" 31 L"sup{vertical-align:super}table{border-spacing:2px}thead,tbody,tfoot{" 32 L"vertical-align:middle}td,th,tr{vertical-align:inherit}s,strike,del{" 33 L"text-decoration:line-through}hr{border:1px inset silver}" 34 L"ol,ul,dir,menu,dd{margin-left:40px}ol{list-style-type:decimal}ol ul,ul " 35 L"ol,ul ul,ol " 36 L"ol{margin-top:0;margin-bottom:0}u,ins{text-decoration:underline}center{" 37 L"text-align:center}" 38 L"ruby{display:ruby}rt{display:ruby-text;font-size:.5em}rb{display:ruby-" 39 L"base}rbc{display:ruby-base-group}rtc{display:ruby-text-group}" 40 L"q:before{content:open-quote}q:after{content:close-quote}" 41 L"rp{display:none}"; 42 return IFDE_CSSStyleSheet::LoadFromBuffer( 43 CFX_WideString(), s_pStyle, FXSYS_wcslen(s_pStyle), FX_CODEPAGE_UTF8); 44 } 45 IFDE_CSSStyleSheet* IFDE_CSSStyleSheet::LoadFromStream( 46 const CFX_WideString& szUrl, 47 IFX_Stream* pStream, 48 FX_WORD wCodePage, 49 FX_DWORD dwMediaList) { 50 CFDE_CSSStyleSheet* pStyleSheet = new CFDE_CSSStyleSheet(dwMediaList); 51 if (!pStyleSheet->LoadFromStream(szUrl, pStream, wCodePage)) { 52 pStyleSheet->Release(); 53 pStyleSheet = NULL; 54 } 55 return pStyleSheet; 56 } 57 IFDE_CSSStyleSheet* IFDE_CSSStyleSheet::LoadFromBuffer( 58 const CFX_WideString& szUrl, 59 const FX_WCHAR* pBuffer, 60 int32_t iBufSize, 61 FX_WORD wCodePage, 62 FX_DWORD dwMediaList) { 63 CFDE_CSSStyleSheet* pStyleSheet = new CFDE_CSSStyleSheet(dwMediaList); 64 if (!pStyleSheet->LoadFromBuffer(szUrl, pBuffer, iBufSize, wCodePage)) { 65 pStyleSheet->Release(); 66 pStyleSheet = NULL; 67 } 68 return pStyleSheet; 69 } 70 CFDE_CSSStyleSheet::CFDE_CSSStyleSheet(FX_DWORD dwMediaList) 71 : m_wCodePage(FX_CODEPAGE_UTF8), 72 m_wRefCount(1), 73 m_dwMediaList(dwMediaList), 74 m_pAllocator(NULL) { 75 FXSYS_assert(m_dwMediaList > 0); 76 } 77 CFDE_CSSStyleSheet::~CFDE_CSSStyleSheet() { 78 Reset(); 79 } 80 void CFDE_CSSStyleSheet::Reset() { 81 for (int32_t i = m_RuleArray.GetSize() - 1; i >= 0; --i) { 82 IFDE_CSSRule* pRule = m_RuleArray.GetAt(i); 83 switch (pRule->GetType()) { 84 case FDE_CSSRULETYPE_Style: 85 ((CFDE_CSSStyleRule*)pRule)->~CFDE_CSSStyleRule(); 86 break; 87 case FDE_CSSRULETYPE_Media: 88 ((CFDE_CSSMediaRule*)pRule)->~CFDE_CSSMediaRule(); 89 break; 90 case FDE_CSSRULETYPE_FontFace: 91 ((CFDE_CSSFontFaceRule*)pRule)->~CFDE_CSSFontFaceRule(); 92 break; 93 default: 94 FXSYS_assert(FALSE); 95 break; 96 } 97 } 98 m_RuleArray.RemoveAll(); 99 m_Selectors.RemoveAll(); 100 m_StringCache.RemoveAll(); 101 if (m_pAllocator) { 102 m_pAllocator->Release(); 103 m_pAllocator = NULL; 104 } 105 } 106 FX_DWORD CFDE_CSSStyleSheet::AddRef() { 107 return ++m_wRefCount; 108 } 109 FX_DWORD CFDE_CSSStyleSheet::Release() { 110 FX_DWORD dwRefCount = --m_wRefCount; 111 if (dwRefCount == 0) { 112 delete this; 113 } 114 return dwRefCount; 115 } 116 int32_t CFDE_CSSStyleSheet::CountRules() const { 117 return m_RuleArray.GetSize(); 118 } 119 IFDE_CSSRule* CFDE_CSSStyleSheet::GetRule(int32_t index) { 120 return m_RuleArray.GetAt(index); 121 } 122 FX_BOOL CFDE_CSSStyleSheet::LoadFromStream(const CFX_WideString& szUrl, 123 IFX_Stream* pStream, 124 FX_WORD wCodePage) { 125 FXSYS_assert(pStream != NULL); 126 IFDE_CSSSyntaxParser* pSyntax = IFDE_CSSSyntaxParser::Create(); 127 if (pSyntax == NULL) { 128 return FALSE; 129 } 130 if (pStream->GetCodePage() != wCodePage) { 131 pStream->SetCodePage(wCodePage); 132 } 133 FX_BOOL bRet = pSyntax->Init(pStream, 4096) && LoadFromSyntax(pSyntax); 134 pSyntax->Release(); 135 m_wCodePage = wCodePage; 136 m_szUrl = szUrl; 137 return bRet; 138 } 139 FX_BOOL CFDE_CSSStyleSheet::LoadFromBuffer(const CFX_WideString& szUrl, 140 const FX_WCHAR* pBuffer, 141 int32_t iBufSize, 142 FX_WORD wCodePage) { 143 FXSYS_assert(pBuffer != NULL && iBufSize > 0); 144 IFDE_CSSSyntaxParser* pSyntax = IFDE_CSSSyntaxParser::Create(); 145 if (pSyntax == NULL) { 146 return FALSE; 147 } 148 FX_BOOL bRet = pSyntax->Init(pBuffer, iBufSize) && LoadFromSyntax(pSyntax); 149 pSyntax->Release(); 150 m_wCodePage = wCodePage; 151 m_szUrl = szUrl; 152 return bRet; 153 } 154 FX_BOOL CFDE_CSSStyleSheet::LoadFromSyntax(IFDE_CSSSyntaxParser* pSyntax) { 155 Reset(); 156 m_pAllocator = FX_CreateAllocator(FX_ALLOCTYPE_Static, 1024, 0); 157 if (m_pAllocator == NULL) { 158 return FALSE; 159 } 160 FDE_CSSSYNTAXSTATUS eStatus; 161 do { 162 switch (eStatus = pSyntax->DoSyntaxParse()) { 163 case FDE_CSSSYNTAXSTATUS_StyleRule: 164 eStatus = LoadStyleRule(pSyntax, m_RuleArray); 165 break; 166 case FDE_CSSSYNTAXSTATUS_MediaRule: 167 eStatus = LoadMediaRule(pSyntax); 168 break; 169 case FDE_CSSSYNTAXSTATUS_FontFaceRule: 170 eStatus = LoadFontFaceRule(pSyntax, m_RuleArray); 171 break; 172 case FDE_CSSSYNTAXSTATUS_ImportRule: 173 eStatus = LoadImportRule(pSyntax); 174 break; 175 case FDE_CSSSYNTAXSTATUS_PageRule: 176 eStatus = LoadPageRule(pSyntax); 177 break; 178 default: 179 break; 180 } 181 } while (eStatus >= FDE_CSSSYNTAXSTATUS_None); 182 m_Selectors.RemoveAll(); 183 m_StringCache.RemoveAll(); 184 return eStatus != FDE_CSSSYNTAXSTATUS_Error; 185 } 186 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadMediaRule( 187 IFDE_CSSSyntaxParser* pSyntax) { 188 FX_DWORD dwMediaList = 0; 189 CFDE_CSSMediaRule* pMediaRule = NULL; 190 for (;;) { 191 switch (pSyntax->DoSyntaxParse()) { 192 case FDE_CSSSYNTAXSTATUS_MediaType: { 193 int32_t iLen; 194 const FX_WCHAR* psz = pSyntax->GetCurrentString(iLen); 195 FDE_LPCCSSMEDIATYPETABLE pMediaType = 196 FDE_GetCSSMediaTypeByName(psz, iLen); 197 if (pMediaType != NULL) { 198 dwMediaList |= pMediaType->wValue; 199 } 200 } break; 201 case FDE_CSSSYNTAXSTATUS_StyleRule: 202 if (pMediaRule == NULL) { 203 SkipRuleSet(pSyntax); 204 } else { 205 FDE_CSSSYNTAXSTATUS eStatus = 206 LoadStyleRule(pSyntax, pMediaRule->GetArray()); 207 if (eStatus < FDE_CSSSYNTAXSTATUS_None) { 208 return eStatus; 209 } 210 } 211 break; 212 case FDE_CSSSYNTAXSTATUS_DeclOpen: 213 if ((dwMediaList & m_dwMediaList) > 0 && pMediaRule == NULL) { 214 pMediaRule = FDE_NewWith(m_pAllocator) CFDE_CSSMediaRule(dwMediaList); 215 m_RuleArray.Add(pMediaRule); 216 } 217 break; 218 case FDE_CSSSYNTAXSTATUS_DeclClose: 219 return FDE_CSSSYNTAXSTATUS_None; 220 FDE_CSSSWITCHDEFAULTS(); 221 } 222 } 223 } 224 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadStyleRule( 225 IFDE_CSSSyntaxParser* pSyntax, 226 CFDE_CSSRuleArray& ruleArray) { 227 m_Selectors.RemoveAt(0, m_Selectors.GetSize()); 228 CFDE_CSSStyleRule* pStyleRule = NULL; 229 const FX_WCHAR* pszValue = NULL; 230 int32_t iValueLen = 0; 231 FDE_CSSPROPERTYARGS propertyArgs; 232 propertyArgs.pStaticStore = m_pAllocator; 233 propertyArgs.pStringCache = &m_StringCache; 234 propertyArgs.pProperty = NULL; 235 CFX_WideString wsName; 236 for (;;) { 237 switch (pSyntax->DoSyntaxParse()) { 238 case FDE_CSSSYNTAXSTATUS_Selector: { 239 pszValue = pSyntax->GetCurrentString(iValueLen); 240 IFDE_CSSSelector* pSelector = 241 CFDE_CSSSelector::FromString(m_pAllocator, pszValue, iValueLen); 242 if (pSelector != NULL) { 243 m_Selectors.Add(pSelector); 244 } 245 } break; 246 case FDE_CSSSYNTAXSTATUS_PropertyName: 247 pszValue = pSyntax->GetCurrentString(iValueLen); 248 propertyArgs.pProperty = FDE_GetCSSPropertyByName(pszValue, iValueLen); 249 if (propertyArgs.pProperty == NULL) { 250 wsName = CFX_WideStringC(pszValue, iValueLen); 251 } 252 break; 253 case FDE_CSSSYNTAXSTATUS_PropertyValue: 254 if (propertyArgs.pProperty != NULL) { 255 pszValue = pSyntax->GetCurrentString(iValueLen); 256 if (iValueLen > 0) { 257 pStyleRule->GetDeclImp().AddProperty(&propertyArgs, pszValue, 258 iValueLen); 259 } 260 } else if (iValueLen > 0) { 261 pszValue = pSyntax->GetCurrentString(iValueLen); 262 if (iValueLen > 0) { 263 pStyleRule->GetDeclImp().AddProperty( 264 &propertyArgs, wsName, wsName.GetLength(), pszValue, iValueLen); 265 } 266 } 267 break; 268 case FDE_CSSSYNTAXSTATUS_DeclOpen: 269 if (pStyleRule == NULL && m_Selectors.GetSize() > 0) { 270 pStyleRule = FDE_NewWith(m_pAllocator) CFDE_CSSStyleRule; 271 pStyleRule->SetSelector(m_pAllocator, m_Selectors); 272 ruleArray.Add(pStyleRule); 273 } else { 274 SkipRuleSet(pSyntax); 275 return FDE_CSSSYNTAXSTATUS_None; 276 } 277 break; 278 case FDE_CSSSYNTAXSTATUS_DeclClose: 279 if (pStyleRule != NULL && 280 pStyleRule->GetDeclImp().GetStartPosition() == NULL) { 281 pStyleRule->~CFDE_CSSStyleRule(); 282 ruleArray.RemoveLast(1); 283 } 284 return FDE_CSSSYNTAXSTATUS_None; 285 FDE_CSSSWITCHDEFAULTS(); 286 } 287 } 288 } 289 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadFontFaceRule( 290 IFDE_CSSSyntaxParser* pSyntax, 291 CFDE_CSSRuleArray& ruleArray) { 292 CFDE_CSSFontFaceRule* pFontFaceRule = NULL; 293 const FX_WCHAR* pszValue = NULL; 294 int32_t iValueLen = 0; 295 FDE_CSSPROPERTYARGS propertyArgs; 296 propertyArgs.pStaticStore = m_pAllocator; 297 propertyArgs.pStringCache = &m_StringCache; 298 propertyArgs.pProperty = NULL; 299 for (;;) { 300 switch (pSyntax->DoSyntaxParse()) { 301 case FDE_CSSSYNTAXSTATUS_PropertyName: 302 pszValue = pSyntax->GetCurrentString(iValueLen); 303 propertyArgs.pProperty = FDE_GetCSSPropertyByName(pszValue, iValueLen); 304 break; 305 case FDE_CSSSYNTAXSTATUS_PropertyValue: 306 if (propertyArgs.pProperty != NULL) { 307 pszValue = pSyntax->GetCurrentString(iValueLen); 308 if (iValueLen > 0) { 309 pFontFaceRule->GetDeclImp().AddProperty(&propertyArgs, pszValue, 310 iValueLen); 311 } 312 } 313 break; 314 case FDE_CSSSYNTAXSTATUS_DeclOpen: 315 if (pFontFaceRule == NULL) { 316 pFontFaceRule = FDE_NewWith(m_pAllocator) CFDE_CSSFontFaceRule; 317 ruleArray.Add(pFontFaceRule); 318 } 319 break; 320 case FDE_CSSSYNTAXSTATUS_DeclClose: 321 return FDE_CSSSYNTAXSTATUS_None; 322 FDE_CSSSWITCHDEFAULTS(); 323 } 324 } 325 return FDE_CSSSYNTAXSTATUS_None; 326 } 327 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadImportRule( 328 IFDE_CSSSyntaxParser* pSyntax) { 329 for (;;) { 330 switch (pSyntax->DoSyntaxParse()) { 331 case FDE_CSSSYNTAXSTATUS_ImportClose: 332 return FDE_CSSSYNTAXSTATUS_None; 333 case FDE_CSSSYNTAXSTATUS_URI: 334 break; 335 FDE_CSSSWITCHDEFAULTS(); 336 } 337 } 338 } 339 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadPageRule( 340 IFDE_CSSSyntaxParser* pSyntax) { 341 return SkipRuleSet(pSyntax); 342 } 343 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::SkipRuleSet( 344 IFDE_CSSSyntaxParser* pSyntax) { 345 for (;;) { 346 switch (pSyntax->DoSyntaxParse()) { 347 case FDE_CSSSYNTAXSTATUS_Selector: 348 case FDE_CSSSYNTAXSTATUS_DeclOpen: 349 case FDE_CSSSYNTAXSTATUS_PropertyName: 350 case FDE_CSSSYNTAXSTATUS_PropertyValue: 351 break; 352 case FDE_CSSSYNTAXSTATUS_DeclClose: 353 return FDE_CSSSYNTAXSTATUS_None; 354 FDE_CSSSWITCHDEFAULTS(); 355 } 356 } 357 return FDE_CSSSYNTAXSTATUS_None; 358 } 359 void CFDE_CSSStyleRule::SetSelector(IFX_MEMAllocator* pStaticStore, 360 const CFDE_CSSSelectorArray& list) { 361 FXSYS_assert(m_ppSelector == NULL); 362 m_iSelectors = list.GetSize(); 363 m_ppSelector = (IFDE_CSSSelector**)pStaticStore->Alloc( 364 m_iSelectors * sizeof(IFDE_CSSSelector*)); 365 for (int32_t i = 0; i < m_iSelectors; ++i) { 366 m_ppSelector[i] = list.GetAt(i); 367 } 368 } 369 CFDE_CSSMediaRule::~CFDE_CSSMediaRule() { 370 for (int32_t i = m_RuleArray.GetSize() - 1; i >= 0; --i) { 371 IFDE_CSSRule* pRule = m_RuleArray.GetAt(i); 372 switch (pRule->GetType()) { 373 case FDE_CSSRULETYPE_Style: 374 ((CFDE_CSSStyleRule*)pRule)->~CFDE_CSSStyleRule(); 375 break; 376 default: 377 FXSYS_assert(FALSE); 378 break; 379 } 380 } 381 } 382 inline FX_BOOL FDE_IsCSSChar(FX_WCHAR wch) { 383 return (wch >= 'a' && wch <= 'z') || (wch >= 'A' && wch <= 'Z'); 384 } 385 int32_t FDE_GetCSSPersudoLen(const FX_WCHAR* psz, const FX_WCHAR* pEnd) { 386 FXSYS_assert(*psz == ':'); 387 const FX_WCHAR* pStart = psz; 388 while (psz < pEnd) { 389 FX_WCHAR wch = *psz; 390 if (FDE_IsCSSChar(wch) || wch == ':') { 391 ++psz; 392 } else { 393 break; 394 } 395 } 396 return psz - pStart; 397 } 398 int32_t FDE_GetCSSNameLen(const FX_WCHAR* psz, const FX_WCHAR* pEnd) { 399 const FX_WCHAR* pStart = psz; 400 while (psz < pEnd) { 401 FX_WCHAR wch = *psz; 402 if (FDE_IsCSSChar(wch) || (wch >= '0' && wch <= '9') || wch == '_' || 403 wch == '-') { 404 ++psz; 405 } else { 406 break; 407 } 408 } 409 return psz - pStart; 410 } 411 IFDE_CSSSelector* CFDE_CSSSelector::FromString(IFX_MEMAllocator* pStaticStore, 412 const FX_WCHAR* psz, 413 int32_t iLen) { 414 FXSYS_assert(pStaticStore != NULL && psz != NULL && iLen > 0); 415 const FX_WCHAR* pStart = psz; 416 const FX_WCHAR* pEnd = psz + iLen; 417 for (; psz < pEnd; ++psz) { 418 switch (*psz) { 419 case '>': 420 case '[': 421 case '+': 422 return NULL; 423 } 424 } 425 CFDE_CSSSelector *pFirst = NULL, *pLast = NULL; 426 CFDE_CSSSelector *pPersudoFirst = NULL, *pPersudoLast = NULL; 427 for (psz = pStart; psz < pEnd;) { 428 FX_WCHAR wch = *psz; 429 if (wch == '.' || wch == '#') { 430 if (psz == pStart || psz[-1] == ' ') { 431 CFDE_CSSSelector* p = FDE_NewWith(pStaticStore) 432 CFDE_CSSSelector(FDE_CSSSELECTORTYPE_Element, L"*", 1, TRUE); 433 if (p == NULL) { 434 return NULL; 435 } 436 if (pFirst != NULL) { 437 pFirst->SetType(FDE_CSSSELECTORTYPE_Descendant); 438 p->SetNext(pFirst); 439 } 440 pFirst = pLast = p; 441 } 442 FXSYS_assert(pLast != NULL); 443 int32_t iNameLen = FDE_GetCSSNameLen(++psz, pEnd); 444 if (iNameLen == 0) { 445 return NULL; 446 } 447 FDE_CSSSELECTORTYPE eType = 448 wch == '.' ? FDE_CSSSELECTORTYPE_Class : FDE_CSSSELECTORTYPE_ID; 449 CFDE_CSSSelector* p = FDE_NewWith(pStaticStore) 450 CFDE_CSSSelector(eType, psz, iNameLen, FALSE); 451 if (p == NULL) { 452 return NULL; 453 } 454 p->SetNext(pLast->GetNextSelector()); 455 pLast->SetNext(p); 456 pLast = p; 457 psz += iNameLen; 458 } else if (FDE_IsCSSChar(wch) || wch == '*') { 459 int32_t iNameLen = wch == '*' ? 1 : FDE_GetCSSNameLen(psz, pEnd); 460 if (iNameLen == 0) { 461 return NULL; 462 } 463 CFDE_CSSSelector* p = FDE_NewWith(pStaticStore) 464 CFDE_CSSSelector(FDE_CSSSELECTORTYPE_Element, psz, iNameLen, TRUE); 465 if (p == NULL) { 466 return NULL; 467 } 468 if (pFirst == NULL) { 469 pFirst = pLast = p; 470 } else { 471 pFirst->SetType(FDE_CSSSELECTORTYPE_Descendant); 472 p->SetNext(pFirst); 473 pFirst = pLast = p; 474 } 475 psz += iNameLen; 476 } else if (wch == ':') { 477 int32_t iNameLen = FDE_GetCSSPersudoLen(psz, pEnd); 478 if (iNameLen == 0) { 479 return NULL; 480 } 481 CFDE_CSSSelector* p = FDE_NewWith(pStaticStore) 482 CFDE_CSSSelector(FDE_CSSSELECTORTYPE_Persudo, psz, iNameLen, TRUE); 483 if (p == NULL) { 484 return NULL; 485 } 486 if (pPersudoFirst == NULL) { 487 pPersudoFirst = pPersudoLast = p; 488 } else { 489 pPersudoLast->SetNext(p); 490 pPersudoLast = p; 491 } 492 psz += iNameLen; 493 } else if (wch == ' ') { 494 psz++; 495 } else { 496 return NULL; 497 } 498 } 499 if (pPersudoFirst == NULL) { 500 return pFirst; 501 } else { 502 pPersudoLast->SetNext(pFirst); 503 return pPersudoFirst; 504 } 505 } 506