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/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