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