blob: 5073434aebd57e09ca82051a90284025e2c27ba4 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#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/rendering/RenderTheme.h"
#include "core/rendering/RenderView.h"
#include "platform/text/LocaleToScriptMapping.h"
namespace WebCore {
// FIXME: This scoping class is a short-term fix to minimize the changes in
// Font-constructing logic.
class FontDescriptionChangeScope {
public:
FontDescriptionChangeScope(FontBuilder* fontBuilder)
: m_fontBuilder(fontBuilder)
, m_fontDescription(fontBuilder->m_style->fontDescription())
{
}
void reset() { m_fontDescription = FontDescription(); }
void set(const FontDescription& fontDescription) { m_fontDescription = fontDescription; }
FontDescription& fontDescription() { return m_fontDescription; }
~FontDescriptionChangeScope()
{
m_fontBuilder->didChangeFontParameters(m_fontBuilder->m_style->setFontDescription(m_fontDescription));
}
private:
FontBuilder* m_fontBuilder;
FontDescription m_fontDescription;
};
FontBuilder::FontBuilder()
: m_document(0)
, m_useSVGZoomRules(false)
, m_fontDirty(false)
{
}
void FontBuilder::initForStyleResolve(const Document& document, RenderStyle* style, bool useSVGZoomRules)
{
// 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());
m_document = &document;
m_useSVGZoomRules = useSVGZoomRules;
m_style = style;
m_fontDirty = false;
}
void FontBuilder::setInitial(float effectiveZoom)
{
ASSERT(m_document && m_document->settings());
if (!m_document || !m_document->settings())
return;
FontDescriptionChangeScope scope(this);
scope.reset();
scope.fontDescription().setGenericFamily(FontDescription::StandardFamily);
scope.fontDescription().setUsePrinterFont(m_document->printing());
const AtomicString& standardFontFamily = m_document->settings()->genericFontFamilySettings().standard();
if (!standardFontFamily.isEmpty()) {
scope.fontDescription().firstFamily().setFamily(standardFontFamily);
scope.fontDescription().firstFamily().appendFamily(0);
}
scope.fontDescription().setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
setSize(scope.fontDescription(), effectiveZoom, FontSize::fontSizeForKeyword(m_document, CSSValueMedium, false));
}
void FontBuilder::inheritFrom(const FontDescription& fontDescription)
{
FontDescriptionChangeScope scope(this);
scope.set(fontDescription);
}
void FontBuilder::didChangeFontParameters(bool changed)
{
m_fontDirty |= changed;
}
void FontBuilder::fromSystemFont(CSSValueID valueId, float effectiveZoom)
{
FontDescriptionChangeScope scope(this);
FontDescription fontDescription;
RenderTheme::theme().systemFont(valueId, fontDescription);
// Double-check and see if the theme did anything. If not, don't bother updating the font.
if (!fontDescription.isAbsoluteSize())
return;
// Make sure the rendering mode and printer font settings are updated.
const Settings* settings = m_document->settings();
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)
{
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());
}
void FontBuilder::setFontFamilyInherit(const FontDescription& parentFontDescription)
{
FontDescriptionChangeScope scope(this);
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)
{
FontDescriptionChangeScope scope(this);
if (!value->isValueList())
return;
FontFamily& firstFamily = scope.fontDescription().firstFamily();
FontFamily* currFamily = 0;
// Before mapping in a new font-family property, we should reset the generic family.
bool oldFamilyUsedFixedDefaultSize = scope.fontDescription().useFixedDefaultSize();
scope.fontDescription().setGenericFamily(FontDescription::NoFamily);
for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
CSSValue* item = i.value();
if (!item->isPrimitiveValue())
continue;
CSSPrimitiveValue* contentValue = toCSSPrimitiveValue(item);
AtomicString face;
Settings* settings = m_document->settings();
if (contentValue->isString()) {
face = AtomicString(contentValue->getStringValue());
} else if (settings) {
switch (contentValue->getValueID()) {
case CSSValueWebkitBody:
face = settings->genericFontFamilySettings().standard();
break;
case CSSValueSerif:
face = FontFamilyNames::webkit_serif;
scope.fontDescription().setGenericFamily(FontDescription::SerifFamily);
break;
case CSSValueSansSerif:
face = FontFamilyNames::webkit_sans_serif;
scope.fontDescription().setGenericFamily(FontDescription::SansSerifFamily);
break;
case CSSValueCursive:
face = FontFamilyNames::webkit_cursive;
scope.fontDescription().setGenericFamily(FontDescription::CursiveFamily);
break;
case CSSValueFantasy:
face = FontFamilyNames::webkit_fantasy;
scope.fontDescription().setGenericFamily(FontDescription::FantasyFamily);
break;
case CSSValueMonospace:
face = FontFamilyNames::webkit_monospace;
scope.fontDescription().setGenericFamily(FontDescription::MonospaceFamily);
break;
case CSSValueWebkitPictograph:
face = FontFamilyNames::webkit_pictograph;
scope.fontDescription().setGenericFamily(FontDescription::PictographFamily);
break;
default:
break;
}
}
if (!face.isEmpty()) {
if (!currFamily) {
// Filling in the first family.
firstFamily.setFamily(face);
firstFamily.appendFamily(0); // 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);
currFamily->appendFamily(newFamily);
currFamily = newFamily.get();
}
}
}
// We can't call useFixedDefaultSize() until all new font families have been added
// If currFamily is non-zero then we set at least one family on this description.
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));
}
void FontBuilder::setFontSizeInitial(float effectiveZoom)
{
FontDescriptionChangeScope scope(this);
float size = FontSize::fontSizeForKeyword(m_document, CSSValueMedium, scope.fontDescription().useFixedDefaultSize());
if (size < 0)
return;
scope.fontDescription().setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
setSize(scope.fontDescription(), effectiveZoom, size);
}
void FontBuilder::setFontSizeInherit(const FontDescription& parentFontDescription, float effectiveZoom)
{
FontDescriptionChangeScope scope(this);
float size = parentFontDescription.specifiedSize();
if (size < 0)
return;
scope.fontDescription().setKeywordSize(parentFontDescription.keywordSize());
setSize(scope.fontDescription(), effectiveZoom, size);
}
// FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large)
// and scale down/up to the next size level.
static float largerFontSize(float size)
{
return size * 1.2f;
}
static float smallerFontSize(float size)
{
return size / 1.2f;
}
// 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)
{
if (!value->isPrimitiveValue())
return;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
FontDescriptionChangeScope scope(this);
scope.fontDescription().setKeywordSize(0);
float parentSize = 0;
bool parentIsAbsoluteSize = false;
float size = 0;
// FIXME: Find out when parentStyle could be 0?
if (parentStyle) {
parentSize = parentStyle->fontDescription().specifiedSize();
parentIsAbsoluteSize = parentStyle->fontDescription().isAbsoluteSize();
}
if (CSSValueID valueID = primitiveValue->getValueID()) {
switch (valueID) {
case CSSValueXxSmall:
case CSSValueXSmall:
case CSSValueSmall:
case CSSValueMedium:
case CSSValueLarge:
case CSSValueXLarge:
case CSSValueXxLarge:
case CSSValueWebkitXxxLarge:
size = FontSize::fontSizeForKeyword(m_document, valueID, scope.fontDescription().useFixedDefaultSize());
scope.fontDescription().setKeywordSize(valueID - CSSValueXxSmall + 1);
break;
case CSSValueLarger:
size = largerFontSize(parentSize);
break;
case CSSValueSmaller:
size = smallerFontSize(parentSize);
break;
default:
return;
}
scope.fontDescription().setIsAbsoluteSize(parentIsAbsoluteSize && (valueID == CSSValueLarger || valueID == CSSValueSmaller));
} else {
scope.fontDescription().setIsAbsoluteSize(parentIsAbsoluteSize || !(primitiveValue->isPercentage() || primitiveValue->isFontRelativeLength()));
if (primitiveValue->isLength())
size = primitiveValue->computeLength<float>(CSSToLengthConversionData(parentStyle, rootElementStyle, 1.0, true));
else if (primitiveValue->isPercentage())
size = (primitiveValue->getFloatValue() * parentSize) / 100.0f;
else if (primitiveValue->isCalculatedPercentageWithLength())
size = primitiveValue->cssCalcValue()->toCalcValue(CSSToLengthConversionData(parentStyle, rootElementStyle, 1.0f))->evaluate(parentSize);
else if (primitiveValue->isViewportPercentageLength())
size = valueForLength(primitiveValue->viewportPercentageLength(), 0, m_document->renderView());
else
return;
}
if (size < 0)
return;
// Overly large font sizes will cause crashes on some platforms (such as Windows).
// Cap font size here to make sure that doesn't happen.
size = std::min(maximumAllowedFontSize, size);
setSize(scope.fontDescription(), effectiveZoom, size);
}
void FontBuilder::setWeight(FontWeight fontWeight)
{
FontDescriptionChangeScope scope(this);
scope.fontDescription().setWeight(fontWeight);
}
void FontBuilder::setWeightBolder()
{
FontDescriptionChangeScope scope(this);
scope.fontDescription().setWeight(scope.fontDescription().bolderWeight());
}
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)
{
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);
}
void FontBuilder::setScript(const String& locale)
{
FontDescriptionChangeScope scope(this);
scope.fontDescription().setScript(localeToScriptCodeForFontSelection(locale));
}
void FontBuilder::setItalic(FontItalic italic)
{
FontDescriptionChangeScope scope(this);
scope.fontDescription().setItalic(italic);
}
void FontBuilder::setSmallCaps(FontSmallCaps smallCaps)
{
FontDescriptionChangeScope scope(this);
scope.fontDescription().setSmallCaps(smallCaps);
}
void FontBuilder::setTextRenderingMode(TextRenderingMode textRenderingMode)
{
FontDescriptionChangeScope scope(this);
scope.fontDescription().setTextRenderingMode(textRenderingMode);
}
void FontBuilder::setKerning(FontDescription::Kerning kerning)
{
FontDescriptionChangeScope scope(this);
scope.fontDescription().setKerning(kerning);
}
void FontBuilder::setFontSmoothing(FontSmoothingMode foontSmoothingMode)
{
FontDescriptionChangeScope scope(this);
scope.fontDescription().setFontSmoothing(foontSmoothingMode);
}
void FontBuilder::setFeatureSettingsNormal()
{
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());
}
void FontBuilder::setSize(FontDescription& fontDescription, float effectiveZoom, float size)
{
fontDescription.setSpecifiedSize(size);
fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription, effectiveZoom, 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();
}
return FontSize::getComputedSizeFromSpecifiedSize(m_document, zoomFactor, fontDescription.isAbsoluteSize(), specifiedSize);
}
static void getFontAndGlyphOrientation(const RenderStyle* style, FontOrientation& fontOrientation, NonCJKGlyphOrientation& glyphOrientation)
{
if (style->isHorizontalWritingMode()) {
fontOrientation = Horizontal;
glyphOrientation = NonCJKGlyphOrientationVerticalRight;
return;
}
switch (style->textOrientation()) {
case TextOrientationVerticalRight:
fontOrientation = Vertical;
glyphOrientation = NonCJKGlyphOrientationVerticalRight;
return;
case TextOrientationUpright:
fontOrientation = Vertical;
glyphOrientation = NonCJKGlyphOrientationUpright;
return;
case TextOrientationSideways:
if (style->writingMode() == LeftToRightWritingMode) {
// FIXME: This should map to sideways-left, which is not supported yet.
fontOrientation = Vertical;
glyphOrientation = NonCJKGlyphOrientationVerticalRight;
return;
}
fontOrientation = Horizontal;
glyphOrientation = NonCJKGlyphOrientationVerticalRight;
return;
case TextOrientationSidewaysRight:
fontOrientation = Horizontal;
glyphOrientation = NonCJKGlyphOrientationVerticalRight;
return;
default:
ASSERT_NOT_REACHED();
fontOrientation = Horizontal;
glyphOrientation = NonCJKGlyphOrientationVerticalRight;
return;
}
}
void FontBuilder::checkForOrientationChange(RenderStyle* style)
{
FontOrientation fontOrientation;
NonCJKGlyphOrientation glyphOrientation;
getFontAndGlyphOrientation(style, fontOrientation, glyphOrientation);
FontDescriptionChangeScope scope(this);
if (scope.fontDescription().orientation() == fontOrientation && scope.fontDescription().nonCJKGlyphOrientation() == glyphOrientation)
return;
scope.fontDescription().setNonCJKGlyphOrientation(glyphOrientation);
scope.fontDescription().setOrientation(fontOrientation);
}
void FontBuilder::checkForGenericFamilyChange(RenderStyle* style, const RenderStyle* parentStyle)
{
FontDescriptionChangeScope scope(this);
if (scope.fontDescription().isAbsoluteSize() || !parentStyle)
return;
const FontDescription& parentFontDescription = parentStyle->fontDescription();
if (scope.fontDescription().useFixedDefaultSize() == parentFontDescription.useFixedDefaultSize())
return;
// For now, lump all families but monospace together.
if (scope.fontDescription().genericFamily() != FontDescription::MonospaceFamily
&& parentFontDescription.genericFamily() != FontDescription::MonospaceFamily)
return;
// We know the parent is monospace or the child is monospace, and that font
// size was unspecified. We want to scale our font size as appropriate.
// If the font uses a keyword size, then we refetch from the table rather than
// multiplying by our scale factor.
float size;
if (scope.fontDescription().keywordSize()) {
size = FontSize::fontSizeForKeyword(m_document, CSSValueXxSmall + scope.fontDescription().keywordSize() - 1, scope.fontDescription().useFixedDefaultSize());
} else {
Settings* settings = m_document->settings();
float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize())
? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize()
: 1;
size = parentFontDescription.useFixedDefaultSize() ?
scope.fontDescription().specifiedSize() / fixedScaleFactor :
scope.fontDescription().specifiedSize() * fixedScaleFactor;
}
setSize(scope.fontDescription(), style->effectiveZoom(), size);
}
void FontBuilder::checkForZoomChange(RenderStyle* style, const RenderStyle* parentStyle)
{
FontDescriptionChangeScope scope(this);
if (style->effectiveZoom() == parentStyle->effectiveZoom())
return;
setSize(scope.fontDescription(), style->effectiveZoom(), scope.fontDescription().specifiedSize());
}
// FIXME: style param should come first
void FontBuilder::createFont(PassRefPtr<FontSelector> fontSelector, const RenderStyle* parentStyle, RenderStyle* style)
{
if (!m_fontDirty)
return;
checkForGenericFamilyChange(style, parentStyle);
checkForZoomChange(style, parentStyle);
checkForOrientationChange(style);
style->font().update(fontSelector);
m_fontDirty = false;
}
void FontBuilder::createFontForDocument(PassRefPtr<FontSelector> fontSelector, RenderStyle* documentStyle)
{
FontDescription fontDescription = FontDescription();
fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle->locale()));
if (Settings* settings = m_document->settings()) {
fontDescription.setUsePrinterFont(m_document->printing());
const AtomicString& standardFont = settings->genericFontFamilySettings().standard(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());
}
FontOrientation fontOrientation;
NonCJKGlyphOrientation glyphOrientation;
getFontAndGlyphOrientation(documentStyle, fontOrientation, glyphOrientation);
fontDescription.setOrientation(fontOrientation);
fontDescription.setNonCJKGlyphOrientation(glyphOrientation);
documentStyle->setFontDescription(fontDescription);
documentStyle->font().update(fontSelector);
}
}