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