Home | History | Annotate | Download | only in resolver
      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/FontFeatureValue.h"
     28 #include "core/css/FontSize.h"
     29 #include "core/page/Frame.h"
     30 #include "core/page/Settings.h"
     31 #include "core/platform/text/LocaleToScriptMapping.h"
     32 #include "core/rendering/RenderTheme.h"
     33 #include "core/rendering/RenderView.h"
     34 
     35 namespace WebCore {
     36 
     37 // FIXME: This scoping class is a short-term fix to minimize the changes in
     38 // Font-constructing logic.
     39 class FontDescriptionChangeScope {
     40 public:
     41     FontDescriptionChangeScope(FontBuilder* fontBuilder)
     42         : m_fontBuilder(fontBuilder)
     43         , m_fontDescription(fontBuilder->m_style->fontDescription())
     44     {
     45     }
     46 
     47     void reset() { m_fontDescription = FontDescription(); }
     48     void set(const FontDescription& fontDescription) { m_fontDescription = fontDescription; }
     49     FontDescription& fontDescription() { return m_fontDescription; }
     50 
     51     ~FontDescriptionChangeScope()
     52     {
     53         m_fontBuilder->didChangeFontParameters(m_fontBuilder->m_style->setFontDescription(m_fontDescription));
     54     }
     55 
     56 private:
     57     FontBuilder* m_fontBuilder;
     58     FontDescription m_fontDescription;
     59 };
     60 
     61 FontBuilder::FontBuilder()
     62     : m_document(0)
     63     , m_useSVGZoomRules(false)
     64     , m_fontDirty(false)
     65 {
     66 }
     67 
     68 void FontBuilder::initForStyleResolve(const Document* document, RenderStyle* style, bool useSVGZoomRules)
     69 {
     70     // All documents need to be in a frame (and thus have access to Settings)
     71     // for style-resolution to make sense.
     72     // Unfortunately SVG Animations currently violate this: crbug.com/260966
     73     // ASSERT(m_document->frame());
     74     m_document = document;
     75     m_useSVGZoomRules = useSVGZoomRules;
     76     m_style = style;
     77     m_fontDirty = false;
     78 }
     79 
     80 void FontBuilder::clear()
     81 {
     82     m_document = 0;
     83     m_style = 0;
     84     m_fontDirty = false;
     85 }
     86 
     87 void FontBuilder::setInitial(float effectiveZoom)
     88 {
     89     ASSERT(m_document && m_document->settings());
     90     if (!m_document || !m_document->settings())
     91         return;
     92 
     93     FontDescriptionChangeScope scope(this);
     94 
     95     scope.reset();
     96     scope.fontDescription().setGenericFamily(FontDescription::StandardFamily);
     97     scope.fontDescription().setUsePrinterFont(m_document->printing());
     98     const AtomicString& standardFontFamily = m_document->settings()->standardFontFamily();
     99     if (!standardFontFamily.isEmpty()) {
    100         scope.fontDescription().firstFamily().setFamily(standardFontFamily);
    101         scope.fontDescription().firstFamily().appendFamily(0);
    102     }
    103     scope.fontDescription().setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
    104     setSize(scope.fontDescription(), effectiveZoom, FontSize::fontSizeForKeyword(m_document, CSSValueMedium, false));
    105 }
    106 
    107 void FontBuilder::inheritFrom(const FontDescription& fontDescription)
    108 {
    109     FontDescriptionChangeScope scope(this);
    110 
    111     scope.set(fontDescription);
    112 }
    113 
    114 void FontBuilder::didChangeFontParameters(bool changed)
    115 {
    116     m_fontDirty |= changed;
    117 }
    118 
    119 void FontBuilder::fromSystemFont(CSSValueID valueId, float effectiveZoom)
    120 {
    121     FontDescriptionChangeScope scope(this);
    122 
    123     FontDescription fontDescription;
    124     RenderTheme::defaultTheme()->systemFont(valueId, fontDescription);
    125 
    126     // Double-check and see if the theme did anything. If not, don't bother updating the font.
    127     if (!fontDescription.isAbsoluteSize())
    128         return;
    129 
    130     // Make sure the rendering mode and printer font settings are updated.
    131     const Settings* settings = m_document->settings();
    132     ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
    133     if (!settings)
    134         return;
    135     fontDescription.setUsePrinterFont(m_document->printing());
    136 
    137     // Handle the zoom factor.
    138     fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, effectiveZoom, fontDescription.specifiedSize()));
    139     scope.set(fontDescription);
    140 }
    141 
    142 void FontBuilder::setFontFamilyInitial(float effectiveZoom)
    143 {
    144     FontDescriptionChangeScope scope(this);
    145 
    146     FontDescription initialDesc = FontDescription();
    147 
    148     // We need to adjust the size to account for the generic family change from monospace to non-monospace.
    149     if (scope.fontDescription().keywordSize() && scope.fontDescription().useFixedDefaultSize())
    150         setSize(scope.fontDescription(), effectiveZoom, FontSize::fontSizeForKeyword(m_document, CSSValueXxSmall + scope.fontDescription().keywordSize() - 1, false));
    151     scope.fontDescription().setGenericFamily(initialDesc.genericFamily());
    152     if (!initialDesc.firstFamily().familyIsEmpty())
    153         scope.fontDescription().setFamily(initialDesc.firstFamily());
    154 }
    155 
    156 void FontBuilder::setFontFamilyInherit(const FontDescription& parentFontDescription)
    157 {
    158     FontDescriptionChangeScope scope(this);
    159 
    160     scope.fontDescription().setGenericFamily(parentFontDescription.genericFamily());
    161     scope.fontDescription().setFamily(parentFontDescription.family());
    162     scope.fontDescription().setIsSpecifiedFont(parentFontDescription.isSpecifiedFont());
    163 }
    164 
    165 // FIXME: I am not convinced FontBuilder needs to know anything about CSSValues.
    166 void FontBuilder::setFontFamilyValue(CSSValue* value, float effectiveZoom)
    167 {
    168     FontDescriptionChangeScope scope(this);
    169 
    170     if (!value->isValueList())
    171         return;
    172 
    173     FontFamily& firstFamily = scope.fontDescription().firstFamily();
    174     FontFamily* currFamily = 0;
    175 
    176     // Before mapping in a new font-family property, we should reset the generic family.
    177     bool oldFamilyUsedFixedDefaultSize = scope.fontDescription().useFixedDefaultSize();
    178     scope.fontDescription().setGenericFamily(FontDescription::NoFamily);
    179 
    180     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
    181         CSSValue* item = i.value();
    182         if (!item->isPrimitiveValue())
    183             continue;
    184         CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item);
    185         AtomicString face;
    186         Settings* settings = m_document->settings();
    187         if (contentValue->isString()) {
    188             face = contentValue->getStringValue();
    189         } else if (settings) {
    190             switch (contentValue->getValueID()) {
    191             case CSSValueWebkitBody:
    192                 face = settings->standardFontFamily();
    193                 break;
    194             case CSSValueSerif:
    195                 face = serifFamily;
    196                 scope.fontDescription().setGenericFamily(FontDescription::SerifFamily);
    197                 break;
    198             case CSSValueSansSerif:
    199                 face = sansSerifFamily;
    200                 scope.fontDescription().setGenericFamily(FontDescription::SansSerifFamily);
    201                 break;
    202             case CSSValueCursive:
    203                 face = cursiveFamily;
    204                 scope.fontDescription().setGenericFamily(FontDescription::CursiveFamily);
    205                 break;
    206             case CSSValueFantasy:
    207                 face = fantasyFamily;
    208                 scope.fontDescription().setGenericFamily(FontDescription::FantasyFamily);
    209                 break;
    210             case CSSValueMonospace:
    211                 face = monospaceFamily;
    212                 scope.fontDescription().setGenericFamily(FontDescription::MonospaceFamily);
    213                 break;
    214             case CSSValueWebkitPictograph:
    215                 face = pictographFamily;
    216                 scope.fontDescription().setGenericFamily(FontDescription::PictographFamily);
    217                 break;
    218             default:
    219                 break;
    220             }
    221         }
    222 
    223         if (!face.isEmpty()) {
    224             if (!currFamily) {
    225                 // Filling in the first family.
    226                 firstFamily.setFamily(face);
    227                 firstFamily.appendFamily(0); // Remove any inherited family-fallback list.
    228                 currFamily = &firstFamily;
    229                 scope.fontDescription().setIsSpecifiedFont(scope.fontDescription().genericFamily() == FontDescription::NoFamily);
    230             } else {
    231                 RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create();
    232                 newFamily->setFamily(face);
    233                 currFamily->appendFamily(newFamily);
    234                 currFamily = newFamily.get();
    235             }
    236         }
    237     }
    238 
    239     // We can't call useFixedDefaultSize() until all new font families have been added
    240     // If currFamily is non-zero then we set at least one family on this description.
    241     if (!currFamily)
    242         return;
    243 
    244     if (scope.fontDescription().keywordSize() && scope.fontDescription().useFixedDefaultSize() != oldFamilyUsedFixedDefaultSize)
    245         setSize(scope.fontDescription(), effectiveZoom, FontSize::fontSizeForKeyword(m_document, CSSValueXxSmall + scope.fontDescription().keywordSize() - 1, !oldFamilyUsedFixedDefaultSize));
    246 }
    247 
    248 void FontBuilder::setFontSizeInitial(float effectiveZoom)
    249 {
    250     FontDescriptionChangeScope scope(this);
    251 
    252     float size = FontSize::fontSizeForKeyword(m_document, CSSValueMedium, scope.fontDescription().useFixedDefaultSize());
    253 
    254     if (size < 0)
    255         return;
    256 
    257     scope.fontDescription().setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
    258     setSize(scope.fontDescription(), effectiveZoom, size);
    259 }
    260 
    261 void FontBuilder::setFontSizeInherit(const FontDescription& parentFontDescription, float effectiveZoom)
    262 {
    263     FontDescriptionChangeScope scope(this);
    264 
    265     float size = parentFontDescription.specifiedSize();
    266 
    267     if (size < 0)
    268         return;
    269 
    270     scope.fontDescription().setKeywordSize(parentFontDescription.keywordSize());
    271     setSize(scope.fontDescription(), effectiveZoom, size);
    272 }
    273 
    274 // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large)
    275 // and scale down/up to the next size level.
    276 static float largerFontSize(float size)
    277 {
    278     return size * 1.2f;
    279 }
    280 
    281 static float smallerFontSize(float size)
    282 {
    283     return size / 1.2f;
    284 }
    285 
    286 // FIXME: Have to pass RenderStyles here for calc/computed values. This shouldn't be neecessary.
    287 void FontBuilder::setFontSizeValue(CSSValue* value, RenderStyle* parentStyle, const RenderStyle* rootElementStyle, float effectiveZoom)
    288 {
    289     if (!value->isPrimitiveValue())
    290         return;
    291 
    292     CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
    293 
    294     FontDescriptionChangeScope scope(this);
    295 
    296     scope.fontDescription().setKeywordSize(0);
    297     float parentSize = 0;
    298     bool parentIsAbsoluteSize = false;
    299     float size = 0;
    300 
    301     // FIXME: Find out when parentStyle could be 0?
    302     if (parentStyle) {
    303         parentSize = parentStyle->fontDescription().specifiedSize();
    304         parentIsAbsoluteSize = parentStyle->fontDescription().isAbsoluteSize();
    305     }
    306 
    307     if (CSSValueID valueID = primitiveValue->getValueID()) {
    308         switch (valueID) {
    309         case CSSValueXxSmall:
    310         case CSSValueXSmall:
    311         case CSSValueSmall:
    312         case CSSValueMedium:
    313         case CSSValueLarge:
    314         case CSSValueXLarge:
    315         case CSSValueXxLarge:
    316         case CSSValueWebkitXxxLarge:
    317             size = FontSize::fontSizeForKeyword(m_document, valueID, scope.fontDescription().useFixedDefaultSize());
    318             scope.fontDescription().setKeywordSize(valueID - CSSValueXxSmall + 1);
    319             break;
    320         case CSSValueLarger:
    321             size = largerFontSize(parentSize);
    322             break;
    323         case CSSValueSmaller:
    324             size = smallerFontSize(parentSize);
    325             break;
    326         default:
    327             return;
    328         }
    329 
    330         scope.fontDescription().setIsAbsoluteSize(parentIsAbsoluteSize && (valueID == CSSValueLarger || valueID == CSSValueSmaller));
    331     } else {
    332         scope.fontDescription().setIsAbsoluteSize(parentIsAbsoluteSize || !(primitiveValue->isPercentage() || primitiveValue->isFontRelativeLength()));
    333         if (primitiveValue->isLength())
    334             size = primitiveValue->computeLength<float>(parentStyle, rootElementStyle, 1.0, true);
    335         else if (primitiveValue->isPercentage())
    336             size = (primitiveValue->getFloatValue() * parentSize) / 100.0f;
    337         else if (primitiveValue->isCalculatedPercentageWithLength())
    338             size = primitiveValue->cssCalcValue()->toCalcValue(parentStyle, rootElementStyle)->evaluate(parentSize);
    339         else if (primitiveValue->isViewportPercentageLength())
    340             size = valueForLength(primitiveValue->viewportPercentageLength(), 0, m_document->renderView());
    341         else
    342             return;
    343     }
    344 
    345     if (size < 0)
    346         return;
    347 
    348     // Overly large font sizes will cause crashes on some platforms (such as Windows).
    349     // Cap font size here to make sure that doesn't happen.
    350     size = std::min(maximumAllowedFontSize, size);
    351 
    352     setSize(scope.fontDescription(), effectiveZoom, size);
    353 }
    354 
    355 void FontBuilder::setWeight(FontWeight fontWeight)
    356 {
    357     FontDescriptionChangeScope scope(this);
    358 
    359     scope.fontDescription().setWeight(fontWeight);
    360 }
    361 
    362 void FontBuilder::setWeightBolder()
    363 {
    364     FontDescriptionChangeScope scope(this);
    365 
    366     scope.fontDescription().setWeight(scope.fontDescription().bolderWeight());
    367 }
    368 
    369 void FontBuilder::setWeightLighter()
    370 {
    371     FontDescriptionChangeScope scope(this);
    372 
    373     scope.fontDescription().setWeight(scope.fontDescription().lighterWeight());
    374 }
    375 
    376 void FontBuilder::setFontVariantLigaturesInitial()
    377 {
    378     FontDescriptionChangeScope scope(this);
    379 
    380     scope.fontDescription().setCommonLigaturesState(FontDescription::NormalLigaturesState);
    381     scope.fontDescription().setDiscretionaryLigaturesState(FontDescription::NormalLigaturesState);
    382     scope.fontDescription().setHistoricalLigaturesState(FontDescription::NormalLigaturesState);
    383 }
    384 
    385 void FontBuilder::setFontVariantLigaturesInherit(const FontDescription& parentFontDescription)
    386 {
    387     FontDescriptionChangeScope scope(this);
    388 
    389     scope.fontDescription().setCommonLigaturesState(parentFontDescription.commonLigaturesState());
    390     scope.fontDescription().setDiscretionaryLigaturesState(parentFontDescription.discretionaryLigaturesState());
    391     scope.fontDescription().setHistoricalLigaturesState(parentFontDescription.historicalLigaturesState());
    392 }
    393 
    394 void FontBuilder::setFontVariantLigaturesValue(CSSValue* value)
    395 {
    396     FontDescriptionChangeScope scope(this);
    397 
    398     FontDescription::LigaturesState commonLigaturesState = FontDescription::NormalLigaturesState;
    399     FontDescription::LigaturesState discretionaryLigaturesState = FontDescription::NormalLigaturesState;
    400     FontDescription::LigaturesState historicalLigaturesState = FontDescription::NormalLigaturesState;
    401 
    402     if (value->isValueList()) {
    403         CSSValueList* valueList = toCSSValueList(value);
    404         for (size_t i = 0; i < valueList->length(); ++i) {
    405             CSSValue* item = valueList->itemWithoutBoundsCheck(i);
    406             ASSERT(item->isPrimitiveValue());
    407             if (item->isPrimitiveValue()) {
    408                 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(item);
    409                 switch (primitiveValue->getValueID()) {
    410                 case CSSValueNoCommonLigatures:
    411                     commonLigaturesState = FontDescription::DisabledLigaturesState;
    412                     break;
    413                 case CSSValueCommonLigatures:
    414                     commonLigaturesState = FontDescription::EnabledLigaturesState;
    415                     break;
    416                 case CSSValueNoDiscretionaryLigatures:
    417                     discretionaryLigaturesState = FontDescription::DisabledLigaturesState;
    418                     break;
    419                 case CSSValueDiscretionaryLigatures:
    420                     discretionaryLigaturesState = FontDescription::EnabledLigaturesState;
    421                     break;
    422                 case CSSValueNoHistoricalLigatures:
    423                     historicalLigaturesState = FontDescription::DisabledLigaturesState;
    424                     break;
    425                 case CSSValueHistoricalLigatures:
    426                     historicalLigaturesState = FontDescription::EnabledLigaturesState;
    427                     break;
    428                 default:
    429                     ASSERT_NOT_REACHED();
    430                     break;
    431                 }
    432             }
    433         }
    434     }
    435 #if !ASSERT_DISABLED
    436     else {
    437         ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue());
    438         ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal);
    439     }
    440 #endif
    441 
    442     scope.fontDescription().setCommonLigaturesState(commonLigaturesState);
    443     scope.fontDescription().setDiscretionaryLigaturesState(discretionaryLigaturesState);
    444     scope.fontDescription().setHistoricalLigaturesState(historicalLigaturesState);
    445 }
    446 
    447 void FontBuilder::setScript(const String& locale)
    448 {
    449     FontDescriptionChangeScope scope(this);
    450 
    451     scope.fontDescription().setScript(localeToScriptCodeForFontSelection(locale));
    452 }
    453 
    454 void FontBuilder::setItalic(FontItalic italic)
    455 {
    456     FontDescriptionChangeScope scope(this);
    457 
    458     scope.fontDescription().setItalic(italic);
    459 }
    460 
    461 void FontBuilder::setSmallCaps(FontSmallCaps smallCaps)
    462 {
    463     FontDescriptionChangeScope scope(this);
    464 
    465     scope.fontDescription().setSmallCaps(smallCaps);
    466 }
    467 
    468 void FontBuilder::setTextRenderingMode(TextRenderingMode textRenderingMode)
    469 {
    470     FontDescriptionChangeScope scope(this);
    471 
    472     scope.fontDescription().setTextRenderingMode(textRenderingMode);
    473 }
    474 
    475 void FontBuilder::setKerning(FontDescription::Kerning kerning)
    476 {
    477     FontDescriptionChangeScope scope(this);
    478 
    479     scope.fontDescription().setKerning(kerning);
    480 }
    481 
    482 void FontBuilder::setFontSmoothing(FontSmoothingMode foontSmoothingMode)
    483 {
    484     FontDescriptionChangeScope scope(this);
    485 
    486     scope.fontDescription().setFontSmoothing(foontSmoothingMode);
    487 }
    488 
    489 void FontBuilder::setFeatureSettingsNormal()
    490 {
    491     FontDescriptionChangeScope scope(this);
    492 
    493     // FIXME: Eliminate FontDescription::makeNormalFeatureSettings. It's useless.
    494     scope.set(scope.fontDescription().makeNormalFeatureSettings());
    495 }
    496 
    497 void FontBuilder::setFeatureSettingsValue(CSSValue* value)
    498 {
    499     FontDescriptionChangeScope scope(this);
    500 
    501     CSSValueList* list = toCSSValueList(value);
    502     RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create();
    503     int len = list->length();
    504     for (int i = 0; i < len; ++i) {
    505         CSSValue* item = list->itemWithoutBoundsCheck(i);
    506         if (!item->isFontFeatureValue())
    507             continue;
    508         FontFeatureValue* feature = static_cast<FontFeatureValue*>(item);
    509         settings->append(FontFeature(feature->tag(), feature->value()));
    510     }
    511     scope.fontDescription().setFeatureSettings(settings.release());
    512 }
    513 
    514 void FontBuilder::setSize(FontDescription& fontDescription, float effectiveZoom, float size)
    515 {
    516     fontDescription.setSpecifiedSize(size);
    517     fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, effectiveZoom, size));
    518 }
    519 
    520 float FontBuilder::getComputedSizeFromSpecifiedSize(FontDescription& fontDescription, float effectiveZoom, float specifiedSize)
    521 {
    522     float zoomFactor = 1.0f;
    523     if (!m_useSVGZoomRules) {
    524         zoomFactor = effectiveZoom;
    525         // FIXME: Why is this here!!!!?!
    526         if (Frame* frame = m_document->frame())
    527             zoomFactor *= frame->textZoomFactor();
    528     }
    529 
    530     return FontSize::getComputedSizeFromSpecifiedSize(m_document, zoomFactor, fontDescription.isAbsoluteSize(), specifiedSize);
    531 }
    532 
    533 static void getFontAndGlyphOrientation(const RenderStyle* style, FontOrientation& fontOrientation, NonCJKGlyphOrientation& glyphOrientation)
    534 {
    535     if (style->isHorizontalWritingMode()) {
    536         fontOrientation = Horizontal;
    537         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
    538         return;
    539     }
    540 
    541     switch (style->textOrientation()) {
    542     case TextOrientationVerticalRight:
    543         fontOrientation = Vertical;
    544         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
    545         return;
    546     case TextOrientationUpright:
    547         fontOrientation = Vertical;
    548         glyphOrientation = NonCJKGlyphOrientationUpright;
    549         return;
    550     case TextOrientationSideways:
    551         if (style->writingMode() == LeftToRightWritingMode) {
    552             // FIXME: This should map to sideways-left, which is not supported yet.
    553             fontOrientation = Vertical;
    554             glyphOrientation = NonCJKGlyphOrientationVerticalRight;
    555             return;
    556         }
    557         fontOrientation = Horizontal;
    558         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
    559         return;
    560     case TextOrientationSidewaysRight:
    561         fontOrientation = Horizontal;
    562         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
    563         return;
    564     default:
    565         ASSERT_NOT_REACHED();
    566         fontOrientation = Horizontal;
    567         glyphOrientation = NonCJKGlyphOrientationVerticalRight;
    568         return;
    569     }
    570 }
    571 
    572 void FontBuilder::checkForOrientationChange(RenderStyle* style)
    573 {
    574     FontOrientation fontOrientation;
    575     NonCJKGlyphOrientation glyphOrientation;
    576     getFontAndGlyphOrientation(style, fontOrientation, glyphOrientation);
    577 
    578     FontDescriptionChangeScope scope(this);
    579 
    580     if (scope.fontDescription().orientation() == fontOrientation && scope.fontDescription().nonCJKGlyphOrientation() == glyphOrientation)
    581         return;
    582 
    583     scope.fontDescription().setNonCJKGlyphOrientation(glyphOrientation);
    584     scope.fontDescription().setOrientation(fontOrientation);
    585 }
    586 
    587 void FontBuilder::checkForGenericFamilyChange(RenderStyle* style, const RenderStyle* parentStyle)
    588 {
    589     FontDescriptionChangeScope scope(this);
    590 
    591     if (scope.fontDescription().isAbsoluteSize() || !parentStyle)
    592         return;
    593 
    594     const FontDescription& parentFontDescription = parentStyle->fontDescription();
    595     if (scope.fontDescription().useFixedDefaultSize() == parentFontDescription.useFixedDefaultSize())
    596         return;
    597 
    598     // For now, lump all families but monospace together.
    599     if (scope.fontDescription().genericFamily() != FontDescription::MonospaceFamily
    600         && parentFontDescription.genericFamily() != FontDescription::MonospaceFamily)
    601         return;
    602 
    603     // We know the parent is monospace or the child is monospace, and that font
    604     // size was unspecified. We want to scale our font size as appropriate.
    605     // If the font uses a keyword size, then we refetch from the table rather than
    606     // multiplying by our scale factor.
    607     float size;
    608     if (scope.fontDescription().keywordSize()) {
    609         size = FontSize::fontSizeForKeyword(m_document, CSSValueXxSmall + scope.fontDescription().keywordSize() - 1, scope.fontDescription().useFixedDefaultSize());
    610     } else {
    611         Settings* settings = m_document->settings();
    612         float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize())
    613             ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize()
    614             : 1;
    615         size = parentFontDescription.useFixedDefaultSize() ?
    616             scope.fontDescription().specifiedSize() / fixedScaleFactor :
    617             scope.fontDescription().specifiedSize() * fixedScaleFactor;
    618     }
    619 
    620     setSize(scope.fontDescription(), style->effectiveZoom(), size);
    621 }
    622 
    623 void FontBuilder::checkForZoomChange(RenderStyle* style, const RenderStyle* parentStyle)
    624 {
    625     FontDescriptionChangeScope scope(this);
    626 
    627     if (style->effectiveZoom() == parentStyle->effectiveZoom())
    628         return;
    629 
    630     setSize(scope.fontDescription(), style->effectiveZoom(), scope.fontDescription().specifiedSize());
    631 }
    632 
    633 // FIXME: style param should come first
    634 void FontBuilder::createFont(PassRefPtr<FontSelector> fontSelector, const RenderStyle* parentStyle, RenderStyle* style)
    635 {
    636     if (!m_fontDirty)
    637         return;
    638 
    639     checkForGenericFamilyChange(style, parentStyle);
    640     checkForZoomChange(style, parentStyle);
    641     checkForOrientationChange(style);
    642     style->font().update(fontSelector);
    643     m_fontDirty = false;
    644 }
    645 
    646 void FontBuilder::createFontForDocument(PassRefPtr<FontSelector> fontSelector, RenderStyle* documentStyle)
    647 {
    648     FontDescription fontDescription = FontDescription();
    649     fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle->locale()));
    650     if (Settings* settings = m_document->settings()) {
    651         fontDescription.setUsePrinterFont(m_document->printing());
    652         const AtomicString& standardFont = settings->standardFontFamily(fontDescription.script());
    653         if (!standardFont.isEmpty()) {
    654             fontDescription.setGenericFamily(FontDescription::StandardFamily);
    655             fontDescription.firstFamily().setFamily(standardFont);
    656             fontDescription.firstFamily().appendFamily(0);
    657         }
    658         fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
    659         int size = FontSize::fontSizeForKeyword(m_document, CSSValueMedium, false);
    660         fontDescription.setSpecifiedSize(size);
    661         fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, documentStyle->effectiveZoom(), size));
    662     } else {
    663         fontDescription.setUsePrinterFont(m_document->printing());
    664     }
    665 
    666     FontOrientation fontOrientation;
    667     NonCJKGlyphOrientation glyphOrientation;
    668     getFontAndGlyphOrientation(documentStyle, fontOrientation, glyphOrientation);
    669     fontDescription.setOrientation(fontOrientation);
    670     fontDescription.setNonCJKGlyphOrientation(glyphOrientation);
    671     documentStyle->setFontDescription(fontDescription);
    672     documentStyle->font().update(fontSelector);
    673 }
    674 
    675 }
    676