1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 4 * Copyright (C) 2013 Google Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #include "config.h" 24 #include "core/css/resolver/FontBuilder.h" 25 26 #include "core/css/CSSCalculationValue.h" 27 #include "core/css/CSSToLengthConversionData.h" 28 #include "core/frame/LocalFrame.h" 29 #include "core/frame/Settings.h" 30 #include "core/rendering/RenderTheme.h" 31 #include "core/rendering/RenderView.h" 32 #include "core/rendering/TextAutosizer.h" 33 #include "platform/fonts/FontDescription.h" 34 #include "platform/text/LocaleToScriptMapping.h" 35 36 namespace blink { 37 38 // FIXME: This scoping class is a short-term fix to minimize the changes in 39 // Font-constructing logic. 40 class FontDescriptionChangeScope { 41 STACK_ALLOCATED(); 42 public: 43 FontDescriptionChangeScope(FontBuilder* fontBuilder) 44 : m_fontBuilder(fontBuilder) 45 , m_fontDescription(fontBuilder->m_style->fontDescription()) 46 { 47 } 48 49 void reset() { m_fontDescription = FontDescription(); } 50 void set(const FontDescription& fontDescription) { m_fontDescription = fontDescription; } 51 FontDescription& fontDescription() { return m_fontDescription; } 52 53 ~FontDescriptionChangeScope() 54 { 55 m_fontBuilder->didChangeFontParameters(m_fontBuilder->m_style->setFontDescription(m_fontDescription)); 56 } 57 58 private: 59 RawPtrWillBeMember<FontBuilder> m_fontBuilder; 60 FontDescription m_fontDescription; 61 }; 62 63 FontBuilder::FontBuilder() 64 : m_document(nullptr) 65 , m_style(0) 66 , m_fontDirty(false) 67 { 68 } 69 70 void FontBuilder::initForStyleResolve(const Document& document, RenderStyle* style) 71 { 72 ASSERT(document.frame()); 73 m_document = &document; 74 m_style = style; 75 m_fontDirty = false; 76 } 77 78 inline static void setFontFamilyToStandard(FontDescription& fontDescription, const Document* document) 79 { 80 if (!document || !document->settings()) 81 return; 82 83 fontDescription.setGenericFamily(FontDescription::StandardFamily); 84 const AtomicString& standardFontFamily = document->settings()->genericFontFamilySettings().standard(); 85 if (standardFontFamily.isEmpty()) 86 return; 87 88 fontDescription.firstFamily().setFamily(standardFontFamily); 89 // FIXME: Why is this needed here? 90 fontDescription.firstFamily().appendFamily(nullptr); 91 } 92 93 void FontBuilder::setInitial(float effectiveZoom) 94 { 95 ASSERT(m_document && m_document->settings()); 96 if (!m_document || !m_document->settings()) 97 return; 98 99 FontDescriptionChangeScope scope(this); 100 101 scope.reset(); 102 setFontFamilyToStandard(scope.fontDescription(), m_document); 103 setSize(scope.fontDescription(), FontBuilder::initialSize()); 104 } 105 106 void FontBuilder::inheritFrom(const FontDescription& fontDescription) 107 { 108 FontDescriptionChangeScope scope(this); 109 110 scope.set(fontDescription); 111 } 112 113 void FontBuilder::didChangeFontParameters(bool changed) 114 { 115 m_fontDirty |= changed; 116 } 117 118 void FontBuilder::fromSystemFont(CSSValueID valueId, float effectiveZoom) 119 { 120 FontDescriptionChangeScope scope(this); 121 122 FontDescription fontDescription; 123 RenderTheme::theme().systemFont(valueId, fontDescription); 124 125 // Double-check and see if the theme did anything. If not, don't bother updating the font. 126 if (!fontDescription.isAbsoluteSize()) 127 return; 128 129 // Make sure the rendering mode and printer font settings are updated. 130 const Settings* settings = m_document->settings(); 131 ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings 132 if (!settings) 133 return; 134 135 // Handle the zoom factor. 136 fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, effectiveZoom, fontDescription.specifiedSize())); 137 scope.set(fontDescription); 138 } 139 140 void FontBuilder::setFontFamilyInitial() 141 { 142 FontDescriptionChangeScope scope(this); 143 144 setFontFamilyToStandard(scope.fontDescription(), m_document); 145 } 146 147 void FontBuilder::setFontFamilyInherit(const FontDescription& parentFontDescription) 148 { 149 FontDescriptionChangeScope scope(this); 150 151 scope.fontDescription().setGenericFamily(parentFontDescription.genericFamily()); 152 scope.fontDescription().setFamily(parentFontDescription.family()); 153 } 154 155 // FIXME: I am not convinced FontBuilder needs to know anything about CSSValues. 156 void FontBuilder::setFontFamilyValue(CSSValue* value) 157 { 158 FontDescriptionChangeScope scope(this); 159 160 if (!value->isValueList()) 161 return; 162 163 FontFamily& firstFamily = scope.fontDescription().firstFamily(); 164 FontFamily* currFamily = 0; 165 166 // Before mapping in a new font-family property, we should reset the generic family. 167 FixedPitchFontType oldFixedPitchFontType = scope.fontDescription().fixedPitchFontType(); 168 scope.fontDescription().setGenericFamily(FontDescription::NoFamily); 169 170 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { 171 CSSValue* item = i.value(); 172 if (!item->isPrimitiveValue()) 173 continue; 174 CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item); 175 AtomicString face; 176 Settings* settings = m_document->settings(); 177 if (contentValue->isString()) { 178 face = AtomicString(contentValue->getStringValue()); 179 } else if (settings) { 180 switch (contentValue->getValueID()) { 181 case CSSValueWebkitBody: 182 face = settings->genericFontFamilySettings().standard(); 183 break; 184 case CSSValueSerif: 185 face = FontFamilyNames::webkit_serif; 186 scope.fontDescription().setGenericFamily(FontDescription::SerifFamily); 187 break; 188 case CSSValueSansSerif: 189 face = FontFamilyNames::webkit_sans_serif; 190 scope.fontDescription().setGenericFamily(FontDescription::SansSerifFamily); 191 break; 192 case CSSValueCursive: 193 face = FontFamilyNames::webkit_cursive; 194 scope.fontDescription().setGenericFamily(FontDescription::CursiveFamily); 195 break; 196 case CSSValueFantasy: 197 face = FontFamilyNames::webkit_fantasy; 198 scope.fontDescription().setGenericFamily(FontDescription::FantasyFamily); 199 break; 200 case CSSValueMonospace: 201 face = FontFamilyNames::webkit_monospace; 202 scope.fontDescription().setGenericFamily(FontDescription::MonospaceFamily); 203 break; 204 case CSSValueWebkitPictograph: 205 face = FontFamilyNames::webkit_pictograph; 206 scope.fontDescription().setGenericFamily(FontDescription::PictographFamily); 207 break; 208 default: 209 break; 210 } 211 } 212 213 if (!face.isEmpty()) { 214 if (!currFamily) { 215 // Filling in the first family. 216 firstFamily.setFamily(face); 217 firstFamily.appendFamily(nullptr); // Remove any inherited family-fallback list. 218 currFamily = &firstFamily; 219 } else { 220 RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create(); 221 newFamily->setFamily(face); 222 currFamily->appendFamily(newFamily); 223 currFamily = newFamily.get(); 224 } 225 } 226 } 227 228 // We can't call useFixedDefaultSize() until all new font families have been added 229 // If currFamily is non-zero then we set at least one family on this description. 230 if (!currFamily) 231 return; 232 233 if (scope.fontDescription().keywordSize() && scope.fontDescription().fixedPitchFontType() != oldFixedPitchFontType) 234 setSize(scope.fontDescription(), FontDescription::Size(scope.fontDescription().keywordSize(), 0.0f, false)); 235 } 236 237 void FontBuilder::setWeight(FontWeight fontWeight) 238 { 239 FontDescriptionChangeScope scope(this); 240 241 scope.fontDescription().setWeight(fontWeight); 242 } 243 244 void FontBuilder::setSize(const FontDescription::Size& size) 245 { 246 FontDescriptionChangeScope scope(this); 247 248 setSize(scope.fontDescription(), size); 249 } 250 251 void FontBuilder::setStretch(FontStretch fontStretch) 252 { 253 FontDescriptionChangeScope scope(this); 254 255 scope.fontDescription().setStretch(fontStretch); 256 } 257 258 void FontBuilder::setScript(const String& locale) 259 { 260 FontDescriptionChangeScope scope(this); 261 262 scope.fontDescription().setLocale(locale); 263 scope.fontDescription().setScript(localeToScriptCodeForFontSelection(locale)); 264 } 265 266 void FontBuilder::setStyle(FontStyle italic) 267 { 268 FontDescriptionChangeScope scope(this); 269 270 scope.fontDescription().setStyle(italic); 271 } 272 273 void FontBuilder::setVariant(FontVariant smallCaps) 274 { 275 FontDescriptionChangeScope scope(this); 276 277 scope.fontDescription().setVariant(smallCaps); 278 } 279 280 void FontBuilder::setVariantLigatures(const FontDescription::VariantLigatures& ligatures) 281 { 282 FontDescriptionChangeScope scope(this); 283 284 scope.fontDescription().setVariantLigatures(ligatures); 285 } 286 287 void FontBuilder::setTextRendering(TextRenderingMode textRenderingMode) 288 { 289 FontDescriptionChangeScope scope(this); 290 291 scope.fontDescription().setTextRendering(textRenderingMode); 292 } 293 294 void FontBuilder::setKerning(FontDescription::Kerning kerning) 295 { 296 FontDescriptionChangeScope scope(this); 297 298 scope.fontDescription().setKerning(kerning); 299 } 300 301 void FontBuilder::setFontSmoothing(FontSmoothingMode foontSmoothingMode) 302 { 303 FontDescriptionChangeScope scope(this); 304 305 scope.fontDescription().setFontSmoothing(foontSmoothingMode); 306 } 307 308 void FontBuilder::setFeatureSettings(PassRefPtr<FontFeatureSettings> settings) 309 { 310 FontDescriptionChangeScope scope(this); 311 312 scope.fontDescription().setFeatureSettings(settings); 313 } 314 315 void FontBuilder::setSize(FontDescription& fontDescription, const FontDescription::Size& size) 316 { 317 float specifiedSize = size.value; 318 319 if (!specifiedSize && size.keyword) 320 specifiedSize = FontSize::fontSizeForKeyword(m_document, size.keyword, fontDescription.fixedPitchFontType()); 321 322 if (specifiedSize < 0) 323 return; 324 325 // Overly large font sizes will cause crashes on some platforms (such as Windows). 326 // Cap font size here to make sure that doesn't happen. 327 specifiedSize = std::min(maximumAllowedFontSize, specifiedSize); 328 329 fontDescription.setKeywordSize(size.keyword); 330 fontDescription.setSpecifiedSize(specifiedSize); 331 fontDescription.setIsAbsoluteSize(size.isAbsolute); 332 } 333 334 float FontBuilder::getComputedSizeFromSpecifiedSize(FontDescription& fontDescription, float effectiveZoom, float specifiedSize) 335 { 336 float zoomFactor = effectiveZoom; 337 // FIXME: Why is this here!!!!?! 338 if (LocalFrame* frame = m_document->frame()) 339 zoomFactor *= frame->textZoomFactor(); 340 341 return FontSize::getComputedSizeFromSpecifiedSize(m_document, zoomFactor, fontDescription.isAbsoluteSize(), specifiedSize); 342 } 343 344 static void getFontAndGlyphOrientation(const RenderStyle* style, FontOrientation& fontOrientation, NonCJKGlyphOrientation& glyphOrientation) 345 { 346 if (style->isHorizontalWritingMode()) { 347 fontOrientation = Horizontal; 348 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 349 return; 350 } 351 352 switch (style->textOrientation()) { 353 case TextOrientationVerticalRight: 354 fontOrientation = Vertical; 355 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 356 return; 357 case TextOrientationUpright: 358 fontOrientation = Vertical; 359 glyphOrientation = NonCJKGlyphOrientationUpright; 360 return; 361 case TextOrientationSideways: 362 if (style->writingMode() == LeftToRightWritingMode) { 363 // FIXME: This should map to sideways-left, which is not supported yet. 364 fontOrientation = Vertical; 365 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 366 return; 367 } 368 fontOrientation = Horizontal; 369 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 370 return; 371 case TextOrientationSidewaysRight: 372 fontOrientation = Horizontal; 373 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 374 return; 375 default: 376 ASSERT_NOT_REACHED(); 377 fontOrientation = Horizontal; 378 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 379 return; 380 } 381 } 382 383 void FontBuilder::checkForOrientationChange(RenderStyle* style) 384 { 385 FontOrientation fontOrientation; 386 NonCJKGlyphOrientation glyphOrientation; 387 getFontAndGlyphOrientation(style, fontOrientation, glyphOrientation); 388 389 FontDescriptionChangeScope scope(this); 390 391 if (scope.fontDescription().orientation() == fontOrientation && scope.fontDescription().nonCJKGlyphOrientation() == glyphOrientation) 392 return; 393 394 scope.fontDescription().setNonCJKGlyphOrientation(glyphOrientation); 395 scope.fontDescription().setOrientation(fontOrientation); 396 } 397 398 void FontBuilder::checkForGenericFamilyChange(RenderStyle* style, const RenderStyle* parentStyle) 399 { 400 FontDescriptionChangeScope scope(this); 401 402 if (scope.fontDescription().isAbsoluteSize() || !parentStyle) 403 return; 404 405 const FontDescription& parentFontDescription = parentStyle->fontDescription(); 406 if (scope.fontDescription().fixedPitchFontType() == parentFontDescription.fixedPitchFontType()) 407 return; 408 409 // For now, lump all families but monospace together. 410 if (scope.fontDescription().genericFamily() != FontDescription::MonospaceFamily 411 && parentFontDescription.genericFamily() != FontDescription::MonospaceFamily) 412 return; 413 414 // We know the parent is monospace or the child is monospace, and that font 415 // size was unspecified. We want to scale our font size as appropriate. 416 // If the font uses a keyword size, then we refetch from the table rather than 417 // multiplying by our scale factor. 418 float size; 419 if (scope.fontDescription().keywordSize()) { 420 size = FontSize::fontSizeForKeyword(m_document, scope.fontDescription().keywordSize(), scope.fontDescription().fixedPitchFontType()); 421 } else { 422 Settings* settings = m_document->settings(); 423 float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize()) 424 ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize() 425 : 1; 426 size = parentFontDescription.fixedPitchFontType() == FixedPitchFont ? 427 scope.fontDescription().specifiedSize() / fixedScaleFactor : 428 scope.fontDescription().specifiedSize() * fixedScaleFactor; 429 } 430 431 scope.fontDescription().setSpecifiedSize(size); 432 updateComputedSize(scope.fontDescription(), style); 433 } 434 435 void FontBuilder::updateComputedSize(RenderStyle* style, const RenderStyle* parentStyle) 436 { 437 FontDescriptionChangeScope scope(this); 438 updateComputedSize(scope.fontDescription(), style); 439 } 440 441 void FontBuilder::updateComputedSize(FontDescription& fontDescription, RenderStyle* style) 442 { 443 float computedSize = getComputedSizeFromSpecifiedSize(fontDescription, style->effectiveZoom(), fontDescription.specifiedSize()); 444 float multiplier = style->textAutosizingMultiplier(); 445 if (multiplier > 1) 446 computedSize = TextAutosizer::computeAutosizedFontSize(computedSize, multiplier); 447 fontDescription.setComputedSize(computedSize); 448 } 449 450 // FIXME: style param should come first 451 void FontBuilder::createFont(PassRefPtrWillBeRawPtr<FontSelector> fontSelector, const RenderStyle* parentStyle, RenderStyle* style) 452 { 453 if (!m_fontDirty) 454 return; 455 456 updateComputedSize(style, parentStyle); 457 checkForGenericFamilyChange(style, parentStyle); 458 checkForOrientationChange(style); 459 style->font().update(fontSelector); 460 m_fontDirty = false; 461 } 462 463 void FontBuilder::createFontForDocument(PassRefPtrWillBeRawPtr<FontSelector> fontSelector, RenderStyle* documentStyle) 464 { 465 FontDescription fontDescription = FontDescription(); 466 fontDescription.setLocale(documentStyle->locale()); 467 fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle->locale())); 468 469 setFontFamilyToStandard(fontDescription, m_document); 470 471 setSize(fontDescription, FontDescription::Size(FontSize::initialKeywordSize(), 0.0f, false)); 472 updateComputedSize(fontDescription, documentStyle); 473 474 FontOrientation fontOrientation; 475 NonCJKGlyphOrientation glyphOrientation; 476 getFontAndGlyphOrientation(documentStyle, fontOrientation, glyphOrientation); 477 fontDescription.setOrientation(fontOrientation); 478 fontDescription.setNonCJKGlyphOrientation(glyphOrientation); 479 documentStyle->setFontDescription(fontDescription); 480 documentStyle->font().update(fontSelector); 481 } 482 483 } 484