#include "core/css/resolver/FontBuilder.h"
#include "core/css/CSSCalculationValue.h"
-#include "core/css/CSSFontFeatureValue.h"
+#include "core/css/CSSToLengthConversionData.h"
#include "core/css/FontSize.h"
-#include "core/frame/Frame.h"
-#include "core/page/Settings.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
#include "core/rendering/RenderTheme.h"
#include "core/rendering/RenderView.h"
+#include "core/rendering/TextAutosizer.h"
+#include "platform/fonts/FontDescription.h"
#include "platform/text/LocaleToScriptMapping.h"
-namespace WebCore {
+namespace blink {
// FIXME: This scoping class is a short-term fix to minimize the changes in
// Font-constructing logic.
class FontDescriptionChangeScope {
+ STACK_ALLOCATED();
public:
FontDescriptionChangeScope(FontBuilder* fontBuilder)
: m_fontBuilder(fontBuilder)
}
private:
- FontBuilder* m_fontBuilder;
+ RawPtrWillBeMember<FontBuilder> m_fontBuilder;
FontDescription m_fontDescription;
};
FontBuilder::FontBuilder()
- : m_document(0)
- , m_useSVGZoomRules(false)
+ : m_document(nullptr)
+ , m_fontSizehasViewportUnits(false)
+ , m_style(0)
, m_fontDirty(false)
{
}
-void FontBuilder::initForStyleResolve(const Document& document, RenderStyle* style, bool useSVGZoomRules)
+void FontBuilder::initForStyleResolve(const Document& document, RenderStyle* style)
{
- // All documents need to be in a frame (and thus have access to Settings)
- // for style-resolution to make sense.
- // Unfortunately SVG Animations currently violate this: crbug.com/260966
- // ASSERT(m_document->frame());
+ ASSERT(document.frame());
m_document = &document;
- m_useSVGZoomRules = useSVGZoomRules;
m_style = style;
m_fontDirty = false;
}
+inline static void setFontFamilyToStandard(FontDescription& fontDescription, const Document* document)
+{
+ if (!document || !document->settings())
+ return;
+
+ fontDescription.setGenericFamily(FontDescription::StandardFamily);
+ const AtomicString& standardFontFamily = document->settings()->genericFontFamilySettings().standard();
+ if (standardFontFamily.isEmpty())
+ return;
+
+ fontDescription.firstFamily().setFamily(standardFontFamily);
+ // FIXME: Why is this needed here?
+ fontDescription.firstFamily().appendFamily(nullptr);
+}
+
void FontBuilder::setInitial(float effectiveZoom)
{
ASSERT(m_document && m_document->settings());
FontDescriptionChangeScope scope(this);
scope.reset();
- scope.fontDescription().setGenericFamily(FontDescription::StandardFamily);
- scope.fontDescription().setUsePrinterFont(m_document->printing());
- const AtomicString& standardFontFamily = m_document->settings()->standardFontFamily();
- if (!standardFontFamily.isEmpty()) {
- scope.fontDescription().firstFamily().setFamily(standardFontFamily);
- scope.fontDescription().firstFamily().appendFamily(0);
- }
+ setFontFamilyToStandard(scope.fontDescription(), m_document);
scope.fontDescription().setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
- setSize(scope.fontDescription(), effectiveZoom, FontSize::fontSizeForKeyword(m_document, CSSValueMedium, false));
+ setSize(scope.fontDescription(), effectiveZoom, FontSize::fontSizeForKeyword(m_document, CSSValueMedium, NonFixedPitchFont));
}
void FontBuilder::inheritFrom(const FontDescription& fontDescription)
ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
if (!settings)
return;
- fontDescription.setUsePrinterFont(m_document->printing());
// Handle the zoom factor.
fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, effectiveZoom, fontDescription.specifiedSize()));
scope.set(fontDescription);
}
-void FontBuilder::setFontFamilyInitial(float effectiveZoom)
+void FontBuilder::setFontFamilyInitial()
{
FontDescriptionChangeScope scope(this);
- FontDescription initialDesc = FontDescription();
-
- // We need to adjust the size to account for the generic family change from monospace to non-monospace.
- if (scope.fontDescription().keywordSize() && scope.fontDescription().useFixedDefaultSize())
- setSize(scope.fontDescription(), effectiveZoom, FontSize::fontSizeForKeyword(m_document, CSSValueXxSmall + scope.fontDescription().keywordSize() - 1, false));
- scope.fontDescription().setGenericFamily(initialDesc.genericFamily());
- if (!initialDesc.firstFamily().familyIsEmpty())
- scope.fontDescription().setFamily(initialDesc.firstFamily());
+ setFontFamilyToStandard(scope.fontDescription(), m_document);
}
void FontBuilder::setFontFamilyInherit(const FontDescription& parentFontDescription)
scope.fontDescription().setGenericFamily(parentFontDescription.genericFamily());
scope.fontDescription().setFamily(parentFontDescription.family());
- scope.fontDescription().setIsSpecifiedFont(parentFontDescription.isSpecifiedFont());
}
// FIXME: I am not convinced FontBuilder needs to know anything about CSSValues.
-void FontBuilder::setFontFamilyValue(CSSValue* value, float effectiveZoom)
+void FontBuilder::setFontFamilyValue(CSSValue* value)
{
FontDescriptionChangeScope scope(this);
FontFamily* currFamily = 0;
// Before mapping in a new font-family property, we should reset the generic family.
- bool oldFamilyUsedFixedDefaultSize = scope.fontDescription().useFixedDefaultSize();
+ FixedPitchFontType oldFixedPitchFontType = scope.fontDescription().fixedPitchFontType();
scope.fontDescription().setGenericFamily(FontDescription::NoFamily);
for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
AtomicString face;
Settings* settings = m_document->settings();
if (contentValue->isString()) {
- face = contentValue->getStringValue();
+ face = AtomicString(contentValue->getStringValue());
} else if (settings) {
switch (contentValue->getValueID()) {
case CSSValueWebkitBody:
- face = settings->standardFontFamily();
+ face = settings->genericFontFamilySettings().standard();
break;
case CSSValueSerif:
face = FontFamilyNames::webkit_serif;
if (!currFamily) {
// Filling in the first family.
firstFamily.setFamily(face);
- firstFamily.appendFamily(0); // Remove any inherited family-fallback list.
+ firstFamily.appendFamily(nullptr); // Remove any inherited family-fallback list.
currFamily = &firstFamily;
- scope.fontDescription().setIsSpecifiedFont(scope.fontDescription().genericFamily() == FontDescription::NoFamily);
} else {
RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create();
newFamily->setFamily(face);
if (!currFamily)
return;
- if (scope.fontDescription().keywordSize() && scope.fontDescription().useFixedDefaultSize() != oldFamilyUsedFixedDefaultSize)
- setSize(scope.fontDescription(), effectiveZoom, FontSize::fontSizeForKeyword(m_document, CSSValueXxSmall + scope.fontDescription().keywordSize() - 1, !oldFamilyUsedFixedDefaultSize));
+ if (scope.fontDescription().keywordSize() && scope.fontDescription().fixedPitchFontType() != oldFixedPitchFontType) {
+ scope.fontDescription().setSpecifiedSize(FontSize::fontSizeForKeyword(m_document,
+ static_cast<CSSValueID>(CSSValueXxSmall + scope.fontDescription().keywordSize() - 1), scope.fontDescription().fixedPitchFontType()));
+ }
}
-void FontBuilder::setFontSizeInitial(float effectiveZoom)
+void FontBuilder::setFontSizeInitial()
{
FontDescriptionChangeScope scope(this);
- float size = FontSize::fontSizeForKeyword(m_document, CSSValueMedium, scope.fontDescription().useFixedDefaultSize());
+ float size = FontSize::fontSizeForKeyword(m_document, CSSValueMedium, scope.fontDescription().fixedPitchFontType());
if (size < 0)
return;
scope.fontDescription().setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
- setSize(scope.fontDescription(), effectiveZoom, size);
+ scope.fontDescription().setSpecifiedSize(size);
}
-void FontBuilder::setFontSizeInherit(const FontDescription& parentFontDescription, float effectiveZoom)
+void FontBuilder::setFontSizeInherit(const FontDescription& parentFontDescription)
{
FontDescriptionChangeScope scope(this);
return;
scope.fontDescription().setKeywordSize(parentFontDescription.keywordSize());
- setSize(scope.fontDescription(), effectiveZoom, size);
+ scope.fontDescription().setSpecifiedSize(size);
}
// FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large)
}
// FIXME: Have to pass RenderStyles here for calc/computed values. This shouldn't be neecessary.
-void FontBuilder::setFontSizeValue(CSSValue* value, RenderStyle* parentStyle, const RenderStyle* rootElementStyle, float effectiveZoom)
+void FontBuilder::setFontSizeValue(CSSValue* value, RenderStyle* parentStyle, const RenderStyle* rootElementStyle)
{
if (!value->isPrimitiveValue())
return;
case CSSValueXLarge:
case CSSValueXxLarge:
case CSSValueWebkitXxxLarge:
- size = FontSize::fontSizeForKeyword(m_document, valueID, scope.fontDescription().useFixedDefaultSize());
+ size = FontSize::fontSizeForKeyword(m_document, valueID, scope.fontDescription().fixedPitchFontType());
scope.fontDescription().setKeywordSize(valueID - CSSValueXxSmall + 1);
break;
case CSSValueLarger:
scope.fontDescription().setIsAbsoluteSize(parentIsAbsoluteSize && (valueID == CSSValueLarger || valueID == CSSValueSmaller));
} else {
scope.fontDescription().setIsAbsoluteSize(parentIsAbsoluteSize || !(primitiveValue->isPercentage() || primitiveValue->isFontRelativeLength()));
- if (primitiveValue->isLength())
- size = primitiveValue->computeLength<float>(parentStyle, rootElementStyle, 1.0, true);
- else if (primitiveValue->isPercentage())
+ if (primitiveValue->isPercentage()) {
size = (primitiveValue->getFloatValue() * parentSize) / 100.0f;
- else if (primitiveValue->isCalculatedPercentageWithLength())
- size = primitiveValue->cssCalcValue()->toCalcValue(parentStyle, rootElementStyle)->evaluate(parentSize);
- else if (primitiveValue->isViewportPercentageLength())
- size = valueForLength(primitiveValue->viewportPercentageLength(), 0, m_document->renderView());
- else
- return;
+ } else {
+ // If we have viewport units the conversion will mark the parent style as having viewport units.
+ bool parentHasViewportUnits = parentStyle->hasViewportUnits();
+ parentStyle->setHasViewportUnits(false);
+ CSSToLengthConversionData conversionData(parentStyle, rootElementStyle, m_document->renderView(), 1.0f, true);
+ if (primitiveValue->isLength())
+ size = primitiveValue->computeLength<float>(conversionData);
+ else if (primitiveValue->isCalculatedPercentageWithLength())
+ size = primitiveValue->cssCalcValue()->toCalcValue(conversionData)->evaluate(parentSize);
+ else
+ ASSERT_NOT_REACHED();
+ m_fontSizehasViewportUnits = parentStyle->hasViewportUnits();
+ parentStyle->setHasViewportUnits(parentHasViewportUnits);
+ }
}
if (size < 0)
// Cap font size here to make sure that doesn't happen.
size = std::min(maximumAllowedFontSize, size);
- setSize(scope.fontDescription(), effectiveZoom, size);
+
+ scope.fontDescription().setSpecifiedSize(size);
}
void FontBuilder::setWeight(FontWeight fontWeight)
scope.fontDescription().setWeight(fontWeight);
}
-void FontBuilder::setWeightBolder()
+void FontBuilder::setStretch(FontStretch fontStretch)
{
FontDescriptionChangeScope scope(this);
- scope.fontDescription().setWeight(scope.fontDescription().bolderWeight());
+ scope.fontDescription().setStretch(fontStretch);
}
-void FontBuilder::setWeightLighter()
-{
- FontDescriptionChangeScope scope(this);
-
- scope.fontDescription().setWeight(scope.fontDescription().lighterWeight());
-}
-
-void FontBuilder::setFontVariantLigaturesInitial()
-{
- FontDescriptionChangeScope scope(this);
-
- scope.fontDescription().setCommonLigaturesState(FontDescription::NormalLigaturesState);
- scope.fontDescription().setDiscretionaryLigaturesState(FontDescription::NormalLigaturesState);
- scope.fontDescription().setHistoricalLigaturesState(FontDescription::NormalLigaturesState);
-}
-
-void FontBuilder::setFontVariantLigaturesInherit(const FontDescription& parentFontDescription)
-{
- FontDescriptionChangeScope scope(this);
-
- scope.fontDescription().setCommonLigaturesState(parentFontDescription.commonLigaturesState());
- scope.fontDescription().setDiscretionaryLigaturesState(parentFontDescription.discretionaryLigaturesState());
- scope.fontDescription().setHistoricalLigaturesState(parentFontDescription.historicalLigaturesState());
-}
-
-void FontBuilder::setFontVariantLigaturesValue(CSSValue* value)
+void FontBuilder::setScript(const String& locale)
{
FontDescriptionChangeScope scope(this);
- FontDescription::LigaturesState commonLigaturesState = FontDescription::NormalLigaturesState;
- FontDescription::LigaturesState discretionaryLigaturesState = FontDescription::NormalLigaturesState;
- FontDescription::LigaturesState historicalLigaturesState = FontDescription::NormalLigaturesState;
-
- if (value->isValueList()) {
- CSSValueList* valueList = toCSSValueList(value);
- for (size_t i = 0; i < valueList->length(); ++i) {
- CSSValue* item = valueList->itemWithoutBoundsCheck(i);
- ASSERT(item->isPrimitiveValue());
- if (item->isPrimitiveValue()) {
- CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(item);
- switch (primitiveValue->getValueID()) {
- case CSSValueNoCommonLigatures:
- commonLigaturesState = FontDescription::DisabledLigaturesState;
- break;
- case CSSValueCommonLigatures:
- commonLigaturesState = FontDescription::EnabledLigaturesState;
- break;
- case CSSValueNoDiscretionaryLigatures:
- discretionaryLigaturesState = FontDescription::DisabledLigaturesState;
- break;
- case CSSValueDiscretionaryLigatures:
- discretionaryLigaturesState = FontDescription::EnabledLigaturesState;
- break;
- case CSSValueNoHistoricalLigatures:
- historicalLigaturesState = FontDescription::DisabledLigaturesState;
- break;
- case CSSValueHistoricalLigatures:
- historicalLigaturesState = FontDescription::EnabledLigaturesState;
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
- }
- }
- }
-#if !ASSERT_DISABLED
- else {
- ASSERT_WITH_SECURITY_IMPLICATION(value->isPrimitiveValue());
- ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueNormal);
- }
-#endif
-
- scope.fontDescription().setCommonLigaturesState(commonLigaturesState);
- scope.fontDescription().setDiscretionaryLigaturesState(discretionaryLigaturesState);
- scope.fontDescription().setHistoricalLigaturesState(historicalLigaturesState);
+ scope.fontDescription().setLocale(locale);
+ scope.fontDescription().setScript(localeToScriptCodeForFontSelection(locale));
}
-void FontBuilder::setScript(const String& locale)
+void FontBuilder::setStyle(FontStyle italic)
{
FontDescriptionChangeScope scope(this);
- scope.fontDescription().setScript(localeToScriptCodeForFontSelection(locale));
+ scope.fontDescription().setStyle(italic);
}
-void FontBuilder::setItalic(FontItalic italic)
+void FontBuilder::setVariant(FontVariant smallCaps)
{
FontDescriptionChangeScope scope(this);
- scope.fontDescription().setItalic(italic);
+ scope.fontDescription().setVariant(smallCaps);
}
-void FontBuilder::setSmallCaps(FontSmallCaps smallCaps)
+void FontBuilder::setVariantLigatures(const FontDescription::VariantLigatures& ligatures)
{
FontDescriptionChangeScope scope(this);
- scope.fontDescription().setSmallCaps(smallCaps);
+ scope.fontDescription().setVariantLigatures(ligatures);
}
-void FontBuilder::setTextRenderingMode(TextRenderingMode textRenderingMode)
+void FontBuilder::setTextRendering(TextRenderingMode textRenderingMode)
{
FontDescriptionChangeScope scope(this);
- scope.fontDescription().setTextRenderingMode(textRenderingMode);
+ scope.fontDescription().setTextRendering(textRenderingMode);
}
void FontBuilder::setKerning(FontDescription::Kerning kerning)
scope.fontDescription().setFontSmoothing(foontSmoothingMode);
}
-void FontBuilder::setFeatureSettingsNormal()
+void FontBuilder::setFeatureSettings(PassRefPtr<FontFeatureSettings> settings)
{
FontDescriptionChangeScope scope(this);
- // FIXME: Eliminate FontDescription::makeNormalFeatureSettings. It's useless.
- scope.set(scope.fontDescription().makeNormalFeatureSettings());
-}
-
-void FontBuilder::setFeatureSettingsValue(CSSValue* value)
-{
- FontDescriptionChangeScope scope(this);
-
- CSSValueList* list = toCSSValueList(value);
- RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create();
- int len = list->length();
- for (int i = 0; i < len; ++i) {
- CSSValue* item = list->itemWithoutBoundsCheck(i);
- if (!item->isFontFeatureValue())
- continue;
- CSSFontFeatureValue* feature = toCSSFontFeatureValue(item);
- settings->append(FontFeature(feature->tag(), feature->value()));
- }
- scope.fontDescription().setFeatureSettings(settings.release());
+ scope.fontDescription().setFeatureSettings(settings);
}
void FontBuilder::setSize(FontDescription& fontDescription, float effectiveZoom, float size)
float FontBuilder::getComputedSizeFromSpecifiedSize(FontDescription& fontDescription, float effectiveZoom, float specifiedSize)
{
- float zoomFactor = 1.0f;
- if (!m_useSVGZoomRules) {
- zoomFactor = effectiveZoom;
- // FIXME: Why is this here!!!!?!
- if (Frame* frame = m_document->frame())
- zoomFactor *= frame->textZoomFactor();
- }
+ float zoomFactor = effectiveZoom;
+ // FIXME: Why is this here!!!!?!
+ if (LocalFrame* frame = m_document->frame())
+ zoomFactor *= frame->textZoomFactor();
return FontSize::getComputedSizeFromSpecifiedSize(m_document, zoomFactor, fontDescription.isAbsoluteSize(), specifiedSize);
}
return;
const FontDescription& parentFontDescription = parentStyle->fontDescription();
- if (scope.fontDescription().useFixedDefaultSize() == parentFontDescription.useFixedDefaultSize())
+ if (scope.fontDescription().fixedPitchFontType() == parentFontDescription.fixedPitchFontType())
return;
// For now, lump all families but monospace together.
// multiplying by our scale factor.
float size;
if (scope.fontDescription().keywordSize()) {
- size = FontSize::fontSizeForKeyword(m_document, CSSValueXxSmall + scope.fontDescription().keywordSize() - 1, scope.fontDescription().useFixedDefaultSize());
+ size = FontSize::fontSizeForKeyword(m_document, static_cast<CSSValueID>(CSSValueXxSmall + scope.fontDescription().keywordSize() - 1), scope.fontDescription().fixedPitchFontType());
} else {
Settings* settings = m_document->settings();
float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize())
? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize()
: 1;
- size = parentFontDescription.useFixedDefaultSize() ?
+ size = parentFontDescription.fixedPitchFontType() == FixedPitchFont ?
scope.fontDescription().specifiedSize() / fixedScaleFactor :
scope.fontDescription().specifiedSize() * fixedScaleFactor;
}
setSize(scope.fontDescription(), style->effectiveZoom(), size);
}
-void FontBuilder::checkForZoomChange(RenderStyle* style, const RenderStyle* parentStyle)
+void FontBuilder::updateComputedSize(RenderStyle* style, const RenderStyle* parentStyle)
{
FontDescriptionChangeScope scope(this);
- if (style->effectiveZoom() == parentStyle->effectiveZoom())
- return;
+ float computedSize = getComputedSizeFromSpecifiedSize(scope.fontDescription(), style->effectiveZoom(), scope.fontDescription().specifiedSize());
+ float multiplier = style->textAutosizingMultiplier();
+ if (multiplier > 1)
+ computedSize = TextAutosizer::computeAutosizedFontSize(computedSize, multiplier);
- setSize(scope.fontDescription(), style->effectiveZoom(), scope.fontDescription().specifiedSize());
+ scope.fontDescription().setComputedSize(computedSize);
}
// FIXME: style param should come first
-void FontBuilder::createFont(PassRefPtr<FontSelector> fontSelector, const RenderStyle* parentStyle, RenderStyle* style)
+void FontBuilder::createFont(PassRefPtrWillBeRawPtr<FontSelector> fontSelector, const RenderStyle* parentStyle, RenderStyle* style)
{
if (!m_fontDirty)
return;
+ updateComputedSize(style, parentStyle);
checkForGenericFamilyChange(style, parentStyle);
- checkForZoomChange(style, parentStyle);
checkForOrientationChange(style);
style->font().update(fontSelector);
m_fontDirty = false;
}
-void FontBuilder::createFontForDocument(PassRefPtr<FontSelector> fontSelector, RenderStyle* documentStyle)
+void FontBuilder::createFontForDocument(PassRefPtrWillBeRawPtr<FontSelector> fontSelector, RenderStyle* documentStyle)
{
FontDescription fontDescription = FontDescription();
+ fontDescription.setLocale(documentStyle->locale());
fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle->locale()));
- if (Settings* settings = m_document->settings()) {
- fontDescription.setUsePrinterFont(m_document->printing());
- const AtomicString& standardFont = settings->standardFontFamily(fontDescription.script());
- if (!standardFont.isEmpty()) {
- fontDescription.setGenericFamily(FontDescription::StandardFamily);
- fontDescription.firstFamily().setFamily(standardFont);
- fontDescription.firstFamily().appendFamily(0);
- }
- fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
- int size = FontSize::fontSizeForKeyword(m_document, CSSValueMedium, false);
- fontDescription.setSpecifiedSize(size);
- fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, documentStyle->effectiveZoom(), size));
- } else {
- fontDescription.setUsePrinterFont(m_document->printing());
- }
+
+ setFontFamilyToStandard(fontDescription, m_document);
+ fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
+ int size = FontSize::fontSizeForKeyword(m_document, CSSValueMedium, NonFixedPitchFont);
+ fontDescription.setSpecifiedSize(size);
+ fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, documentStyle->effectiveZoom(), size));
FontOrientation fontOrientation;
NonCJKGlyphOrientation glyphOrientation;