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 "core/fxcrt/css/cfx_cssdeclaration.h" 8 9 #include "core/fxcrt/css/cfx_csscolorvalue.h" 10 #include "core/fxcrt/css/cfx_csscustomproperty.h" 11 #include "core/fxcrt/css/cfx_cssenumvalue.h" 12 #include "core/fxcrt/css/cfx_cssnumbervalue.h" 13 #include "core/fxcrt/css/cfx_csspropertyholder.h" 14 #include "core/fxcrt/css/cfx_cssstringvalue.h" 15 #include "core/fxcrt/css/cfx_cssvaluelist.h" 16 #include "core/fxcrt/css/cfx_cssvaluelistparser.h" 17 #include "core/fxcrt/fx_extension.h" 18 #include "third_party/base/logging.h" 19 #include "third_party/base/ptr_util.h" 20 21 namespace { 22 23 uint8_t Hex2Dec(uint8_t hexHigh, uint8_t hexLow) { 24 return (FXSYS_HexCharToInt(hexHigh) << 4) + FXSYS_HexCharToInt(hexLow); 25 } 26 27 struct CFX_CSSPropertyValueTable { 28 CFX_CSSPropertyValue eName; 29 const wchar_t* pszName; 30 uint32_t dwHash; 31 }; 32 const CFX_CSSPropertyValueTable g_CFX_CSSPropertyValues[] = { 33 {CFX_CSSPropertyValue::Bolder, L"bolder", 0x009F1058}, 34 {CFX_CSSPropertyValue::None, L"none", 0x048B6670}, 35 {CFX_CSSPropertyValue::Dot, L"dot", 0x0A48CB27}, 36 {CFX_CSSPropertyValue::Sub, L"sub", 0x0BD37FAA}, 37 {CFX_CSSPropertyValue::Top, L"top", 0x0BEDAF33}, 38 {CFX_CSSPropertyValue::Right, L"right", 0x193ADE3E}, 39 {CFX_CSSPropertyValue::Normal, L"normal", 0x247CF3E9}, 40 {CFX_CSSPropertyValue::Auto, L"auto", 0x2B35B6D9}, 41 {CFX_CSSPropertyValue::Text, L"text", 0x2D08AF85}, 42 {CFX_CSSPropertyValue::XSmall, L"x-small", 0x2D2FCAFE}, 43 {CFX_CSSPropertyValue::Thin, L"thin", 0x2D574D53}, 44 {CFX_CSSPropertyValue::Small, L"small", 0x316A3739}, 45 {CFX_CSSPropertyValue::Bottom, L"bottom", 0x399F02B5}, 46 {CFX_CSSPropertyValue::Underline, L"underline", 0x3A0273A6}, 47 {CFX_CSSPropertyValue::Double, L"double", 0x3D98515B}, 48 {CFX_CSSPropertyValue::Lighter, L"lighter", 0x45BEB7AF}, 49 {CFX_CSSPropertyValue::Oblique, L"oblique", 0x53EBDDB1}, 50 {CFX_CSSPropertyValue::Super, L"super", 0x6A4F842F}, 51 {CFX_CSSPropertyValue::Center, L"center", 0x6C51AFC1}, 52 {CFX_CSSPropertyValue::XxLarge, L"xx-large", 0x70BB1508}, 53 {CFX_CSSPropertyValue::Smaller, L"smaller", 0x849769F0}, 54 {CFX_CSSPropertyValue::Baseline, L"baseline", 0x87436BA3}, 55 {CFX_CSSPropertyValue::Thick, L"thick", 0x8CC35EB3}, 56 {CFX_CSSPropertyValue::Justify, L"justify", 0x8D269CAE}, 57 {CFX_CSSPropertyValue::Middle, L"middle", 0x947FA00F}, 58 {CFX_CSSPropertyValue::Medium, L"medium", 0xA084A381}, 59 {CFX_CSSPropertyValue::ListItem, L"list-item", 0xA32382B8}, 60 {CFX_CSSPropertyValue::XxSmall, L"xx-small", 0xADE1FC76}, 61 {CFX_CSSPropertyValue::Bold, L"bold", 0xB18313A1}, 62 {CFX_CSSPropertyValue::SmallCaps, L"small-caps", 0xB299428D}, 63 {CFX_CSSPropertyValue::Inline, L"inline", 0xC02D649F}, 64 {CFX_CSSPropertyValue::Overline, L"overline", 0xC0EC9FA4}, 65 {CFX_CSSPropertyValue::TextBottom, L"text-bottom", 0xC7D08D87}, 66 {CFX_CSSPropertyValue::Larger, L"larger", 0xCD3C409D}, 67 {CFX_CSSPropertyValue::InlineTable, L"inline-table", 0xD131F494}, 68 {CFX_CSSPropertyValue::InlineBlock, L"inline-block", 0xD26A8BD7}, 69 {CFX_CSSPropertyValue::Blink, L"blink", 0xDC36E390}, 70 {CFX_CSSPropertyValue::Block, L"block", 0xDCD480AB}, 71 {CFX_CSSPropertyValue::Italic, L"italic", 0xE31D5396}, 72 {CFX_CSSPropertyValue::LineThrough, L"line-through", 0xE4C5A276}, 73 {CFX_CSSPropertyValue::XLarge, L"x-large", 0xF008E390}, 74 {CFX_CSSPropertyValue::Large, L"large", 0xF4434FCB}, 75 {CFX_CSSPropertyValue::Left, L"left", 0xF5AD782B}, 76 {CFX_CSSPropertyValue::TextTop, L"text-top", 0xFCB58D45}, 77 }; 78 const int32_t g_iCSSPropertyValueCount = 79 sizeof(g_CFX_CSSPropertyValues) / sizeof(CFX_CSSPropertyValueTable); 80 static_assert(g_iCSSPropertyValueCount == 81 static_cast<int32_t>(CFX_CSSPropertyValue::LAST_MARKER), 82 "Property value table differs in size from property value enum"); 83 84 struct CFX_CSSLengthUnitTable { 85 uint16_t wHash; 86 CFX_CSSNumberType wValue; 87 }; 88 const CFX_CSSLengthUnitTable g_CFX_CSSLengthUnits[] = { 89 {0x0672, CFX_CSSNumberType::EMS}, 90 {0x067D, CFX_CSSNumberType::EXS}, 91 {0x1AF7, CFX_CSSNumberType::Inches}, 92 {0x2F7A, CFX_CSSNumberType::MilliMeters}, 93 {0x3ED3, CFX_CSSNumberType::Picas}, 94 {0x3EE4, CFX_CSSNumberType::Points}, 95 {0x3EE8, CFX_CSSNumberType::Pixels}, 96 {0xFC30, CFX_CSSNumberType::CentiMeters}, 97 }; 98 99 struct CFX_CSSColorTable { 100 uint32_t dwHash; 101 FX_ARGB dwValue; 102 }; 103 const CFX_CSSColorTable g_CFX_CSSColors[] = { 104 {0x031B47FE, 0xff000080}, {0x0BB8DF5B, 0xffff0000}, 105 {0x0D82A78C, 0xff800000}, {0x2ACC82E8, 0xff00ffff}, 106 {0x2D083986, 0xff008080}, {0x4A6A6195, 0xffc0c0c0}, 107 {0x546A8EF3, 0xff808080}, {0x65C9169C, 0xffffa500}, 108 {0x8422BB61, 0xffffffff}, {0x9271A558, 0xff800080}, 109 {0xA65A3EE3, 0xffff00ff}, {0xB1345708, 0xff0000ff}, 110 {0xB6D2CF1F, 0xff808000}, {0xD19B5E1C, 0xffffff00}, 111 {0xDB64391D, 0xff000000}, {0xF616D507, 0xff00ff00}, 112 {0xF6EFFF31, 0xff008000}, 113 }; 114 115 const CFX_CSSPropertyValueTable* GetCSSPropertyValueByName( 116 const WideStringView& wsName) { 117 ASSERT(!wsName.IsEmpty()); 118 uint32_t dwHash = FX_HashCode_GetW(wsName, true); 119 int32_t iEnd = g_iCSSPropertyValueCount; 120 int32_t iMid, iStart = 0; 121 uint32_t dwMid; 122 do { 123 iMid = (iStart + iEnd) / 2; 124 dwMid = g_CFX_CSSPropertyValues[iMid].dwHash; 125 if (dwHash == dwMid) { 126 return g_CFX_CSSPropertyValues + iMid; 127 } else if (dwHash > dwMid) { 128 iStart = iMid + 1; 129 } else { 130 iEnd = iMid - 1; 131 } 132 } while (iStart <= iEnd); 133 return nullptr; 134 } 135 136 const CFX_CSSLengthUnitTable* GetCSSLengthUnitByName( 137 const WideStringView& wsName) { 138 ASSERT(!wsName.IsEmpty()); 139 uint16_t wHash = FX_HashCode_GetW(wsName, true); 140 int32_t iEnd = 141 sizeof(g_CFX_CSSLengthUnits) / sizeof(CFX_CSSLengthUnitTable) - 1; 142 int32_t iMid, iStart = 0; 143 uint16_t wMid; 144 do { 145 iMid = (iStart + iEnd) / 2; 146 wMid = g_CFX_CSSLengthUnits[iMid].wHash; 147 if (wHash == wMid) { 148 return g_CFX_CSSLengthUnits + iMid; 149 } else if (wHash > wMid) { 150 iStart = iMid + 1; 151 } else { 152 iEnd = iMid - 1; 153 } 154 } while (iStart <= iEnd); 155 return nullptr; 156 } 157 158 const CFX_CSSColorTable* GetCSSColorByName(const WideStringView& wsName) { 159 ASSERT(!wsName.IsEmpty()); 160 uint32_t dwHash = FX_HashCode_GetW(wsName, true); 161 int32_t iEnd = sizeof(g_CFX_CSSColors) / sizeof(CFX_CSSColorTable) - 1; 162 int32_t iMid, iStart = 0; 163 uint32_t dwMid; 164 do { 165 iMid = (iStart + iEnd) / 2; 166 dwMid = g_CFX_CSSColors[iMid].dwHash; 167 if (dwHash == dwMid) { 168 return g_CFX_CSSColors + iMid; 169 } else if (dwHash > dwMid) { 170 iStart = iMid + 1; 171 } else { 172 iEnd = iMid - 1; 173 } 174 } while (iStart <= iEnd); 175 return nullptr; 176 } 177 178 bool ParseCSSNumber(const wchar_t* pszValue, 179 int32_t iValueLen, 180 float& fValue, 181 CFX_CSSNumberType& eUnit) { 182 ASSERT(pszValue && iValueLen > 0); 183 int32_t iUsedLen = 0; 184 fValue = FXSYS_wcstof(pszValue, iValueLen, &iUsedLen); 185 if (iUsedLen <= 0) 186 return false; 187 188 iValueLen -= iUsedLen; 189 pszValue += iUsedLen; 190 eUnit = CFX_CSSNumberType::Number; 191 if (iValueLen >= 1 && *pszValue == '%') { 192 eUnit = CFX_CSSNumberType::Percent; 193 } else if (iValueLen == 2) { 194 const CFX_CSSLengthUnitTable* pUnit = 195 GetCSSLengthUnitByName(WideStringView(pszValue, 2)); 196 if (pUnit) 197 eUnit = pUnit->wValue; 198 } 199 return true; 200 } 201 202 } // namespace 203 204 // static 205 bool CFX_CSSDeclaration::ParseCSSString(const wchar_t* pszValue, 206 int32_t iValueLen, 207 int32_t* iOffset, 208 int32_t* iLength) { 209 ASSERT(pszValue && iValueLen > 0); 210 *iOffset = 0; 211 *iLength = iValueLen; 212 if (iValueLen >= 2) { 213 wchar_t first = pszValue[0], last = pszValue[iValueLen - 1]; 214 if ((first == '\"' && last == '\"') || (first == '\'' && last == '\'')) { 215 *iOffset = 1; 216 *iLength -= 2; 217 } 218 } 219 return iValueLen > 0; 220 } 221 222 // static. 223 bool CFX_CSSDeclaration::ParseCSSColor(const wchar_t* pszValue, 224 int32_t iValueLen, 225 FX_ARGB* dwColor) { 226 ASSERT(pszValue && iValueLen > 0); 227 ASSERT(dwColor); 228 229 if (*pszValue == '#') { 230 switch (iValueLen) { 231 case 4: { 232 uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[1]); 233 uint8_t green = Hex2Dec((uint8_t)pszValue[2], (uint8_t)pszValue[2]); 234 uint8_t blue = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[3]); 235 *dwColor = ArgbEncode(255, red, green, blue); 236 return true; 237 } 238 case 7: { 239 uint8_t red = Hex2Dec((uint8_t)pszValue[1], (uint8_t)pszValue[2]); 240 uint8_t green = Hex2Dec((uint8_t)pszValue[3], (uint8_t)pszValue[4]); 241 uint8_t blue = Hex2Dec((uint8_t)pszValue[5], (uint8_t)pszValue[6]); 242 *dwColor = ArgbEncode(255, red, green, blue); 243 return true; 244 } 245 default: 246 return false; 247 } 248 } 249 250 if (iValueLen >= 10) { 251 if (pszValue[iValueLen - 1] != ')' || FXSYS_wcsnicmp(L"rgb(", pszValue, 4)) 252 return false; 253 254 uint8_t rgb[3] = {0}; 255 float fValue; 256 CFX_CSSPrimitiveType eType; 257 CFX_CSSValueListParser list(pszValue + 4, iValueLen - 5, ','); 258 for (int32_t i = 0; i < 3; ++i) { 259 if (!list.NextValue(&eType, &pszValue, &iValueLen)) 260 return false; 261 if (eType != CFX_CSSPrimitiveType::Number) 262 return false; 263 CFX_CSSNumberType eNumType; 264 if (!ParseCSSNumber(pszValue, iValueLen, fValue, eNumType)) 265 return false; 266 267 rgb[i] = eNumType == CFX_CSSNumberType::Percent 268 ? FXSYS_round(fValue * 2.55f) 269 : FXSYS_round(fValue); 270 } 271 *dwColor = ArgbEncode(255, rgb[0], rgb[1], rgb[2]); 272 return true; 273 } 274 275 const CFX_CSSColorTable* pColor = 276 GetCSSColorByName(WideStringView(pszValue, iValueLen)); 277 if (!pColor) 278 return false; 279 280 *dwColor = pColor->dwValue; 281 return true; 282 } 283 284 CFX_CSSDeclaration::CFX_CSSDeclaration() {} 285 286 CFX_CSSDeclaration::~CFX_CSSDeclaration() {} 287 288 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::GetProperty( 289 CFX_CSSProperty eProperty, 290 bool* bImportant) const { 291 for (const auto& p : properties_) { 292 if (p->eProperty == eProperty) { 293 *bImportant = p->bImportant; 294 return p->pValue; 295 } 296 } 297 return nullptr; 298 } 299 300 void CFX_CSSDeclaration::AddPropertyHolder(CFX_CSSProperty eProperty, 301 RetainPtr<CFX_CSSValue> pValue, 302 bool bImportant) { 303 auto pHolder = pdfium::MakeUnique<CFX_CSSPropertyHolder>(); 304 pHolder->bImportant = bImportant; 305 pHolder->eProperty = eProperty; 306 pHolder->pValue = pValue; 307 properties_.push_back(std::move(pHolder)); 308 } 309 310 void CFX_CSSDeclaration::AddProperty(const CFX_CSSPropertyTable* pTable, 311 const WideStringView& value) { 312 ASSERT(!value.IsEmpty()); 313 314 const wchar_t* pszValue = value.unterminated_c_str(); 315 int32_t iValueLen = value.GetLength(); 316 bool bImportant = false; 317 if (iValueLen >= 10 && pszValue[iValueLen - 10] == '!' && 318 FXSYS_wcsnicmp(L"important", pszValue + iValueLen - 9, 9) == 0) { 319 if ((iValueLen -= 10) == 0) 320 return; 321 322 bImportant = true; 323 } 324 const uint32_t dwType = pTable->dwType; 325 switch (dwType & 0x0F) { 326 case CFX_CSSVALUETYPE_Primitive: { 327 static const uint32_t g_ValueGuessOrder[] = { 328 CFX_CSSVALUETYPE_MaybeNumber, CFX_CSSVALUETYPE_MaybeEnum, 329 CFX_CSSVALUETYPE_MaybeColor, CFX_CSSVALUETYPE_MaybeString, 330 }; 331 static const int32_t g_ValueGuessCount = 332 sizeof(g_ValueGuessOrder) / sizeof(uint32_t); 333 for (int32_t i = 0; i < g_ValueGuessCount; ++i) { 334 const uint32_t dwMatch = dwType & g_ValueGuessOrder[i]; 335 if (dwMatch == 0) { 336 continue; 337 } 338 RetainPtr<CFX_CSSValue> pCSSValue; 339 switch (dwMatch) { 340 case CFX_CSSVALUETYPE_MaybeNumber: 341 pCSSValue = ParseNumber(pszValue, iValueLen); 342 break; 343 case CFX_CSSVALUETYPE_MaybeEnum: 344 pCSSValue = ParseEnum(pszValue, iValueLen); 345 break; 346 case CFX_CSSVALUETYPE_MaybeColor: 347 pCSSValue = ParseColor(pszValue, iValueLen); 348 break; 349 case CFX_CSSVALUETYPE_MaybeString: 350 pCSSValue = ParseString(pszValue, iValueLen); 351 break; 352 default: 353 break; 354 } 355 if (pCSSValue) { 356 AddPropertyHolder(pTable->eName, pCSSValue, bImportant); 357 return; 358 } 359 360 if ((dwType & ~(g_ValueGuessOrder[i])) == CFX_CSSVALUETYPE_Primitive) 361 return; 362 } 363 break; 364 } 365 case CFX_CSSVALUETYPE_Shorthand: { 366 RetainPtr<CFX_CSSValue> pWidth; 367 switch (pTable->eName) { 368 case CFX_CSSProperty::Font: 369 ParseFontProperty(pszValue, iValueLen, bImportant); 370 return; 371 case CFX_CSSProperty::Border: 372 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { 373 AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth, 374 bImportant); 375 AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth, 376 bImportant); 377 AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth, 378 bImportant); 379 AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth, 380 bImportant); 381 return; 382 } 383 break; 384 case CFX_CSSProperty::BorderLeft: 385 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { 386 AddPropertyHolder(CFX_CSSProperty::BorderLeftWidth, pWidth, 387 bImportant); 388 return; 389 } 390 break; 391 case CFX_CSSProperty::BorderTop: 392 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { 393 AddPropertyHolder(CFX_CSSProperty::BorderTopWidth, pWidth, 394 bImportant); 395 return; 396 } 397 break; 398 case CFX_CSSProperty::BorderRight: 399 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { 400 AddPropertyHolder(CFX_CSSProperty::BorderRightWidth, pWidth, 401 bImportant); 402 return; 403 } 404 break; 405 case CFX_CSSProperty::BorderBottom: 406 if (ParseBorderProperty(pszValue, iValueLen, pWidth)) { 407 AddPropertyHolder(CFX_CSSProperty::BorderBottomWidth, pWidth, 408 bImportant); 409 return; 410 } 411 break; 412 default: 413 break; 414 } 415 } break; 416 case CFX_CSSVALUETYPE_List: 417 ParseValueListProperty(pTable, pszValue, iValueLen, bImportant); 418 return; 419 default: 420 NOTREACHED(); 421 break; 422 } 423 } 424 425 void CFX_CSSDeclaration::AddProperty(const WideString& prop, 426 const WideString& value) { 427 custom_properties_.push_back( 428 pdfium::MakeUnique<CFX_CSSCustomProperty>(prop, value)); 429 } 430 431 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseNumber(const wchar_t* pszValue, 432 int32_t iValueLen) { 433 float fValue; 434 CFX_CSSNumberType eUnit; 435 if (!ParseCSSNumber(pszValue, iValueLen, fValue, eUnit)) 436 return nullptr; 437 return pdfium::MakeRetain<CFX_CSSNumberValue>(eUnit, fValue); 438 } 439 440 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseEnum(const wchar_t* pszValue, 441 int32_t iValueLen) { 442 const CFX_CSSPropertyValueTable* pValue = 443 GetCSSPropertyValueByName(WideStringView(pszValue, iValueLen)); 444 return pValue ? pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName) : nullptr; 445 } 446 447 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseColor(const wchar_t* pszValue, 448 int32_t iValueLen) { 449 FX_ARGB dwColor; 450 if (!ParseCSSColor(pszValue, iValueLen, &dwColor)) 451 return nullptr; 452 return pdfium::MakeRetain<CFX_CSSColorValue>(dwColor); 453 } 454 455 RetainPtr<CFX_CSSValue> CFX_CSSDeclaration::ParseString(const wchar_t* pszValue, 456 int32_t iValueLen) { 457 int32_t iOffset; 458 if (!ParseCSSString(pszValue, iValueLen, &iOffset, &iValueLen)) 459 return nullptr; 460 461 if (iValueLen <= 0) 462 return nullptr; 463 464 return pdfium::MakeRetain<CFX_CSSStringValue>( 465 WideString(pszValue + iOffset, iValueLen)); 466 } 467 468 void CFX_CSSDeclaration::ParseValueListProperty( 469 const CFX_CSSPropertyTable* pTable, 470 const wchar_t* pszValue, 471 int32_t iValueLen, 472 bool bImportant) { 473 wchar_t separator = 474 (pTable->eName == CFX_CSSProperty::FontFamily) ? ',' : ' '; 475 CFX_CSSValueListParser parser(pszValue, iValueLen, separator); 476 477 const uint32_t dwType = pTable->dwType; 478 CFX_CSSPrimitiveType eType; 479 std::vector<RetainPtr<CFX_CSSValue>> list; 480 while (parser.NextValue(&eType, &pszValue, &iValueLen)) { 481 switch (eType) { 482 case CFX_CSSPrimitiveType::Number: 483 if (dwType & CFX_CSSVALUETYPE_MaybeNumber) { 484 float fValue; 485 CFX_CSSNumberType eNumType; 486 if (ParseCSSNumber(pszValue, iValueLen, fValue, eNumType)) 487 list.push_back( 488 pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue)); 489 } 490 break; 491 case CFX_CSSPrimitiveType::String: 492 if (dwType & CFX_CSSVALUETYPE_MaybeColor) { 493 FX_ARGB dwColor; 494 if (ParseCSSColor(pszValue, iValueLen, &dwColor)) { 495 list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor)); 496 continue; 497 } 498 } 499 if (dwType & CFX_CSSVALUETYPE_MaybeEnum) { 500 const CFX_CSSPropertyValueTable* pValue = 501 GetCSSPropertyValueByName(WideStringView(pszValue, iValueLen)); 502 if (pValue) { 503 list.push_back(pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName)); 504 continue; 505 } 506 } 507 if (dwType & CFX_CSSVALUETYPE_MaybeString) { 508 list.push_back(pdfium::MakeRetain<CFX_CSSStringValue>( 509 WideString(pszValue, iValueLen))); 510 } 511 break; 512 case CFX_CSSPrimitiveType::RGB: 513 if (dwType & CFX_CSSVALUETYPE_MaybeColor) { 514 FX_ARGB dwColor; 515 if (ParseCSSColor(pszValue, iValueLen, &dwColor)) { 516 list.push_back(pdfium::MakeRetain<CFX_CSSColorValue>(dwColor)); 517 } 518 } 519 break; 520 default: 521 break; 522 } 523 } 524 if (list.empty()) 525 return; 526 527 switch (pTable->eName) { 528 case CFX_CSSProperty::BorderWidth: 529 Add4ValuesProperty(list, bImportant, CFX_CSSProperty::BorderLeftWidth, 530 CFX_CSSProperty::BorderTopWidth, 531 CFX_CSSProperty::BorderRightWidth, 532 CFX_CSSProperty::BorderBottomWidth); 533 return; 534 case CFX_CSSProperty::Margin: 535 Add4ValuesProperty(list, bImportant, CFX_CSSProperty::MarginLeft, 536 CFX_CSSProperty::MarginTop, 537 CFX_CSSProperty::MarginRight, 538 CFX_CSSProperty::MarginBottom); 539 return; 540 case CFX_CSSProperty::Padding: 541 Add4ValuesProperty(list, bImportant, CFX_CSSProperty::PaddingLeft, 542 CFX_CSSProperty::PaddingTop, 543 CFX_CSSProperty::PaddingRight, 544 CFX_CSSProperty::PaddingBottom); 545 return; 546 default: { 547 auto pList = pdfium::MakeRetain<CFX_CSSValueList>(list); 548 AddPropertyHolder(pTable->eName, pList, bImportant); 549 return; 550 } 551 } 552 } 553 554 void CFX_CSSDeclaration::Add4ValuesProperty( 555 const std::vector<RetainPtr<CFX_CSSValue>>& list, 556 bool bImportant, 557 CFX_CSSProperty eLeft, 558 CFX_CSSProperty eTop, 559 CFX_CSSProperty eRight, 560 CFX_CSSProperty eBottom) { 561 switch (list.size()) { 562 case 1: 563 AddPropertyHolder(eLeft, list[0], bImportant); 564 AddPropertyHolder(eTop, list[0], bImportant); 565 AddPropertyHolder(eRight, list[0], bImportant); 566 AddPropertyHolder(eBottom, list[0], bImportant); 567 return; 568 case 2: 569 AddPropertyHolder(eLeft, list[1], bImportant); 570 AddPropertyHolder(eTop, list[0], bImportant); 571 AddPropertyHolder(eRight, list[1], bImportant); 572 AddPropertyHolder(eBottom, list[0], bImportant); 573 return; 574 case 3: 575 AddPropertyHolder(eLeft, list[1], bImportant); 576 AddPropertyHolder(eTop, list[0], bImportant); 577 AddPropertyHolder(eRight, list[1], bImportant); 578 AddPropertyHolder(eBottom, list[2], bImportant); 579 return; 580 case 4: 581 AddPropertyHolder(eLeft, list[3], bImportant); 582 AddPropertyHolder(eTop, list[0], bImportant); 583 AddPropertyHolder(eRight, list[1], bImportant); 584 AddPropertyHolder(eBottom, list[2], bImportant); 585 return; 586 default: 587 break; 588 } 589 } 590 591 bool CFX_CSSDeclaration::ParseBorderProperty( 592 const wchar_t* pszValue, 593 int32_t iValueLen, 594 RetainPtr<CFX_CSSValue>& pWidth) const { 595 pWidth.Reset(nullptr); 596 597 CFX_CSSValueListParser parser(pszValue, iValueLen, ' '); 598 CFX_CSSPrimitiveType eType; 599 while (parser.NextValue(&eType, &pszValue, &iValueLen)) { 600 switch (eType) { 601 case CFX_CSSPrimitiveType::Number: { 602 if (pWidth) 603 continue; 604 605 float fValue; 606 CFX_CSSNumberType eNumType; 607 if (ParseCSSNumber(pszValue, iValueLen, fValue, eNumType)) 608 pWidth = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue); 609 break; 610 } 611 case CFX_CSSPrimitiveType::String: { 612 const CFX_CSSColorTable* pColorItem = 613 GetCSSColorByName(WideStringView(pszValue, iValueLen)); 614 if (pColorItem) 615 continue; 616 617 const CFX_CSSPropertyValueTable* pValue = 618 GetCSSPropertyValueByName(WideStringView(pszValue, iValueLen)); 619 if (!pValue) 620 continue; 621 622 switch (pValue->eName) { 623 case CFX_CSSPropertyValue::Thin: 624 case CFX_CSSPropertyValue::Thick: 625 case CFX_CSSPropertyValue::Medium: 626 if (!pWidth) 627 pWidth = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 628 break; 629 default: 630 break; 631 } 632 break; 633 } 634 default: 635 break; 636 } 637 } 638 if (!pWidth) 639 pWidth = 640 pdfium::MakeRetain<CFX_CSSNumberValue>(CFX_CSSNumberType::Number, 0.0f); 641 642 return true; 643 } 644 645 void CFX_CSSDeclaration::ParseFontProperty(const wchar_t* pszValue, 646 int32_t iValueLen, 647 bool bImportant) { 648 CFX_CSSValueListParser parser(pszValue, iValueLen, '/'); 649 RetainPtr<CFX_CSSValue> pStyle; 650 RetainPtr<CFX_CSSValue> pVariant; 651 RetainPtr<CFX_CSSValue> pWeight; 652 RetainPtr<CFX_CSSValue> pFontSize; 653 RetainPtr<CFX_CSSValue> pLineHeight; 654 std::vector<RetainPtr<CFX_CSSValue>> familyList; 655 CFX_CSSPrimitiveType eType; 656 while (parser.NextValue(&eType, &pszValue, &iValueLen)) { 657 switch (eType) { 658 case CFX_CSSPrimitiveType::String: { 659 const CFX_CSSPropertyValueTable* pValue = 660 GetCSSPropertyValueByName(WideStringView(pszValue, iValueLen)); 661 if (pValue) { 662 switch (pValue->eName) { 663 case CFX_CSSPropertyValue::XxSmall: 664 case CFX_CSSPropertyValue::XSmall: 665 case CFX_CSSPropertyValue::Small: 666 case CFX_CSSPropertyValue::Medium: 667 case CFX_CSSPropertyValue::Large: 668 case CFX_CSSPropertyValue::XLarge: 669 case CFX_CSSPropertyValue::XxLarge: 670 case CFX_CSSPropertyValue::Smaller: 671 case CFX_CSSPropertyValue::Larger: 672 if (!pFontSize) 673 pFontSize = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 674 continue; 675 case CFX_CSSPropertyValue::Bold: 676 case CFX_CSSPropertyValue::Bolder: 677 case CFX_CSSPropertyValue::Lighter: 678 if (!pWeight) 679 pWeight = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 680 continue; 681 case CFX_CSSPropertyValue::Italic: 682 case CFX_CSSPropertyValue::Oblique: 683 if (!pStyle) 684 pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 685 continue; 686 case CFX_CSSPropertyValue::SmallCaps: 687 if (!pVariant) 688 pVariant = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 689 continue; 690 case CFX_CSSPropertyValue::Normal: 691 if (!pStyle) 692 pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 693 else if (!pVariant) 694 pVariant = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 695 else if (!pWeight) 696 pWeight = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 697 else if (!pFontSize) 698 pFontSize = pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 699 else if (!pLineHeight) 700 pLineHeight = 701 pdfium::MakeRetain<CFX_CSSEnumValue>(pValue->eName); 702 continue; 703 default: 704 break; 705 } 706 } 707 if (pFontSize) { 708 familyList.push_back(pdfium::MakeRetain<CFX_CSSStringValue>( 709 WideString(pszValue, iValueLen))); 710 } 711 parser.UseCommaSeparator(); 712 break; 713 } 714 case CFX_CSSPrimitiveType::Number: { 715 float fValue; 716 CFX_CSSNumberType eNumType; 717 if (!ParseCSSNumber(pszValue, iValueLen, fValue, eNumType)) 718 break; 719 if (eType == CFX_CSSPrimitiveType::Number) { 720 switch ((int32_t)fValue) { 721 case 100: 722 case 200: 723 case 300: 724 case 400: 725 case 500: 726 case 600: 727 case 700: 728 case 800: 729 case 900: 730 if (!pWeight) 731 pWeight = pdfium::MakeRetain<CFX_CSSNumberValue>( 732 CFX_CSSNumberType::Number, fValue); 733 continue; 734 } 735 } 736 if (!pFontSize) 737 pFontSize = pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue); 738 else if (!pLineHeight) 739 pLineHeight = 740 pdfium::MakeRetain<CFX_CSSNumberValue>(eNumType, fValue); 741 break; 742 } 743 default: 744 break; 745 } 746 } 747 748 if (!pStyle) { 749 pStyle = pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal); 750 } 751 if (!pVariant) { 752 pVariant = 753 pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal); 754 } 755 if (!pWeight) { 756 pWeight = 757 pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal); 758 } 759 if (!pFontSize) { 760 pFontSize = 761 pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Medium); 762 } 763 if (!pLineHeight) { 764 pLineHeight = 765 pdfium::MakeRetain<CFX_CSSEnumValue>(CFX_CSSPropertyValue::Normal); 766 } 767 768 AddPropertyHolder(CFX_CSSProperty::FontStyle, pStyle, bImportant); 769 AddPropertyHolder(CFX_CSSProperty::FontVariant, pVariant, bImportant); 770 AddPropertyHolder(CFX_CSSProperty::FontWeight, pWeight, bImportant); 771 AddPropertyHolder(CFX_CSSProperty::FontSize, pFontSize, bImportant); 772 AddPropertyHolder(CFX_CSSProperty::LineHeight, pLineHeight, bImportant); 773 if (!familyList.empty()) { 774 auto pList = pdfium::MakeRetain<CFX_CSSValueList>(familyList); 775 AddPropertyHolder(CFX_CSSProperty::FontFamily, pList, bImportant); 776 } 777 } 778 779 size_t CFX_CSSDeclaration::PropertyCountForTesting() const { 780 return properties_.size(); 781 } 782