| /* |
| * Copyright (C) 2016 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "Font.h" |
| |
| #if USE(DIRECT2D) |
| |
| #include "DirectWriteUtilities.h" |
| #include "FloatRect.h" |
| #include "FontCache.h" |
| #include "FontDescription.h" |
| #include "GlyphPage.h" |
| #include "GraphicsContext.h" |
| #include "HWndDC.h" |
| #include "NotImplemented.h" |
| #include <comutil.h> |
| #include <dwrite_3.h> |
| #include <mlang.h> |
| #include <unicode/uchar.h> |
| #include <unicode/unorm.h> |
| #include <winsock2.h> |
| #include <wtf/MathExtras.h> |
| #include <wtf/RetainPtr.h> |
| #include <wtf/text/WTFString.h> |
| |
| namespace WebCore { |
| |
| static Vector<WCHAR> getFaceName(IDWriteFont* font) |
| { |
| if (!font) |
| return Vector<WCHAR>(); |
| |
| COMPtr<IDWriteLocalizedStrings> localizedFaceNames; |
| HRESULT hr = font->GetFaceNames(&localizedFaceNames); |
| RELEASE_ASSERT(SUCCEEDED(hr)); |
| |
| UINT32 localeIndex = 0; |
| BOOL exists = false; |
| |
| wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; |
| int localeLength = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH); |
| if (localeLength) |
| hr = localizedFaceNames->FindLocaleName(localeName, &localeIndex, &exists); |
| |
| if (!exists || !SUCCEEDED(hr)) |
| hr = localizedFaceNames->FindLocaleName(L"en-us", &localeIndex, &exists); |
| |
| if (!exists || !SUCCEEDED(hr)) |
| localeIndex = 0; |
| |
| UINT32 faceNameLength = 0; |
| hr = localizedFaceNames->GetStringLength(localeIndex, &faceNameLength); |
| if (!SUCCEEDED(hr)) |
| return Vector<WCHAR>(); |
| |
| Vector<WCHAR> faceName(faceNameLength + 1); |
| hr = localizedFaceNames->GetString(localeIndex, faceName.data(), faceName.size()); |
| |
| return faceName; |
| } |
| |
| void Font::platformInit() |
| { |
| m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; |
| m_scriptCache = 0; |
| m_scriptFontProperties = 0; |
| |
| if (m_platformData.useGDI()) |
| return initGDIFont(); |
| |
| float pointSize = m_platformData.size(); |
| |
| auto font = m_platformData.dwFont(); |
| RELEASE_ASSERT(font); |
| |
| auto fontFace = m_platformData.dwFontFace(); |
| RELEASE_ASSERT(fontFace); |
| |
| DWRITE_FONT_METRICS fontMetrics; |
| font->GetMetrics(&fontMetrics); |
| |
| int iAscent = fontMetrics.ascent; |
| int iDescent = fontMetrics.descent; |
| int iLineGap = fontMetrics.lineGap; |
| int iCapHeight = fontMetrics.capHeight; |
| |
| unsigned unitsPerEm = fontMetrics.designUnitsPerEm; |
| float fAscent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize; |
| float fDescent = scaleEmToUnits(iDescent, unitsPerEm) * pointSize; |
| float fCapHeight = scaleEmToUnits(iCapHeight, unitsPerEm) * pointSize; |
| float fLineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize; |
| |
| if (origin() == Origin::Local) { |
| Vector<WCHAR> faceName = getFaceName(font); |
| fAscent = ascentConsideringMacAscentHack(faceName.data(), fAscent, fDescent); |
| } |
| |
| m_fontMetrics.setAscent(fAscent); |
| m_fontMetrics.setDescent(fDescent); |
| m_fontMetrics.setCapHeight(fCapHeight); |
| m_fontMetrics.setLineGap(fLineGap); |
| m_fontMetrics.setLineSpacing(lroundf(fAscent) + lroundf(fDescent) + lroundf(fLineGap)); |
| |
| Glyph xGlyph = glyphDataForCharacter('x').glyph; |
| |
| if (xGlyph) { |
| // Measure the actual character "x", since it's possible for it to extend below the baseline, and we need the |
| // reported x-height to only include the portion of the glyph that is above the baseline. |
| Vector<DWRITE_GLYPH_METRICS> glyphMetrics(1); |
| HRESULT hr = fontFace->GetDesignGlyphMetrics(&xGlyph, 1, glyphMetrics.data(), m_platformData.orientation() == FontOrientation::Vertical); |
| RELEASE_ASSERT(SUCCEEDED(hr)); |
| m_fontMetrics.setXHeight(scaleEmToUnits(glyphMetrics.first().verticalOriginY, unitsPerEm) * pointSize); |
| } else { |
| int iXHeight = fontMetrics.xHeight; |
| m_fontMetrics.setXHeight(scaleEmToUnits(iXHeight, unitsPerEm) * pointSize); |
| } |
| |
| m_fontMetrics.setUnitsPerEm(unitsPerEm); |
| } |
| |
| FloatRect Font::platformBoundsForGlyph(Glyph glyph) const |
| { |
| if (!platformData().size()) |
| return FloatRect(); |
| |
| if (m_platformData.useGDI()) |
| return boundsForGDIGlyph(glyph); |
| |
| auto font = m_platformData.dwFont(); |
| RELEASE_ASSERT(font); |
| |
| auto fontFace = m_platformData.dwFontFace(); |
| RELEASE_ASSERT(fontFace); |
| |
| float pointSize = m_platformData.size(); |
| bool vertical = m_platformData.orientation() == FontOrientation::Vertical; |
| |
| Vector<DWRITE_GLYPH_METRICS> glyphMetrics(1); |
| HRESULT hr = fontFace->GetDesignGlyphMetrics(&glyph, 1, glyphMetrics.data(), m_platformData.orientation() == FontOrientation::Vertical); |
| RELEASE_ASSERT(SUCCEEDED(hr)); |
| |
| const auto& metrics = glyphMetrics.first(); |
| |
| unsigned unitsPerEm = m_fontMetrics.unitsPerEm(); |
| |
| FloatPoint origin(scaleEmToUnits(metrics.leftSideBearing, unitsPerEm) * pointSize, scaleEmToUnits(metrics.verticalOriginY, unitsPerEm) * pointSize); |
| FloatSize size(scaleEmToUnits(metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing, unitsPerEm) * pointSize, |
| scaleEmToUnits(metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing, unitsPerEm) * pointSize); |
| |
| FloatRect boundingBox(origin, size); |
| if (m_syntheticBoldOffset) |
| boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset); |
| |
| return boundingBox; |
| } |
| |
| float Font::platformWidthForGlyph(Glyph glyph) const |
| { |
| if (!platformData().size()) |
| return 0; |
| |
| if (m_platformData.useGDI()) |
| return widthForGDIGlyph(glyph); |
| |
| auto font = m_platformData.dwFont(); |
| RELEASE_ASSERT(font); |
| |
| auto fontFace = m_platformData.dwFontFace(); |
| RELEASE_ASSERT(fontFace); |
| |
| bool isVertical = m_platformData.orientation() == FontOrientation::Vertical; |
| |
| Vector<DWRITE_GLYPH_METRICS> glyphMetrics(1); |
| HRESULT hr = fontFace->GetDesignGlyphMetrics(&glyph, 1, glyphMetrics.data(), isVertical); |
| RELEASE_ASSERT(SUCCEEDED(hr)); |
| |
| const auto& metrics = glyphMetrics.first(); |
| int widthInEm = metrics.advanceWidth; |
| |
| float pointSize = m_platformData.size(); |
| unsigned unitsPerEm = m_fontMetrics.unitsPerEm(); |
| float width = scaleEmToUnits(widthInEm, unitsPerEm) * pointSize; |
| |
| return width + m_syntheticBoldOffset; |
| } |
| |
| Path Font::platformPathForGlyph(Glyph) const |
| { |
| notImplemented(); |
| return Path(); |
| } |
| |
| } |
| |
| #endif |