blob: 91112d965c89ba7d4c57be7c693eca17726859af [file] [log] [blame]
/*
* 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 "FontCascade.h"
#if USE(DIRECT2D)
#include "AffineTransform.h"
#include "COMPtr.h"
#include "FloatConversion.h"
#include "Font.h"
#include "GlyphBuffer.h"
#include "GraphicsContext.h"
#include "GraphicsContextPlatformPrivateDirect2D.h"
#include "IntRect.h"
#include "PlatformContextDirect2D.h"
#include "UniscribeController.h"
#include "WebCoreTextRenderer.h"
#include <d2d1.h>
#include <dwrite_3.h>
#include <wtf/MathExtras.h>
namespace WebCore {
void FontCascade::drawGlyphs(GraphicsContext& graphicsContext, const Font& font, const GlyphBuffer& glyphBuffer,
unsigned from, unsigned numGlyphs, const FloatPoint& point, FontSmoothingMode smoothingMode)
{
auto context = graphicsContext.platformContext()->renderTarget();
bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();
switch (smoothingMode) {
case FontSmoothingMode::Antialiased:
graphicsContext.setShouldAntialias(true);
shouldUseFontSmoothing = false;
break;
case FontSmoothingMode::SubpixelAntialiased:
graphicsContext.setShouldAntialias(true);
shouldUseFontSmoothing = true;
break;
case FontSmoothingMode::NoSmoothing:
graphicsContext.setShouldAntialias(false);
shouldUseFontSmoothing = false;
break;
case FontSmoothingMode::AutoSmoothing:
// For the AutoSmooth case, don't do anything! Keep the default settings.
break;
default:
ASSERT_NOT_REACHED();
}
const FontPlatformData& platformData = font.platformData();
graphicsContext.save();
D2D1_MATRIX_3X2_F matrix;
context->GetTransform(&matrix);
if (platformData.syntheticOblique()) {
static float skew = -tanf(syntheticObliqueAngle() * piFloat / 180.0f);
auto skewMatrix = D2D1::Matrix3x2F::Skew(skew, 0);
context->SetTransform(matrix * skewMatrix);
}
RELEASE_ASSERT(platformData.dwFont());
RELEASE_ASSERT(platformData.dwFontFace());
Vector<FLOAT> horizontalAdvances(numGlyphs);
Vector<DWRITE_GLYPH_OFFSET> offsetAdvances(numGlyphs);
for (unsigned i = 0; i < numGlyphs; ++i) {
if (i + from >= glyphBuffer.advancesCount())
break;
auto advance = glyphBuffer.advances(i + from);
if (!advance)
continue;
horizontalAdvances[i] = advance->width();
offsetAdvances[i].advanceOffset = advance->width();
offsetAdvances[i].ascenderOffset = advance->height();
}
DWRITE_GLYPH_RUN glyphRun;
glyphRun.fontFace = platformData.dwFontFace();
glyphRun.fontEmSize = platformData.size();
glyphRun.glyphCount = numGlyphs;
glyphRun.glyphIndices = glyphBuffer.glyphs(from);
glyphRun.glyphAdvances = horizontalAdvances.data();
glyphRun.glyphOffsets = nullptr;
glyphRun.isSideways = platformData.orientation() == FontOrientation::Vertical;
glyphRun.bidiLevel = 0;
FloatSize shadowOffset;
float shadowBlur;
Color shadowColor;
graphicsContext.getShadow(shadowOffset, shadowBlur, shadowColor);
bool hasSimpleShadow = graphicsContext.textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && (!graphicsContext.shadowsIgnoreTransforms() || graphicsContext.getCTM().isIdentityOrTranslationOrFlipped());
if (hasSimpleShadow) {
// Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
graphicsContext.clearShadow();
Color fillColor = graphicsContext.fillColor();
Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
float shadowTextX = point.x() + shadowOffset.width();
// If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative.
float shadowTextY = point.y() + shadowOffset.height() * (graphicsContext.shadowsIgnoreTransforms() ? -1 : 1);
auto shadowBrush = graphicsContext.brushWithColor(shadowFillColor);
context->DrawGlyphRun(D2D1::Point2F(shadowTextX, shadowTextY), &glyphRun, shadowBrush);
if (font.syntheticBoldOffset())
context->DrawGlyphRun(D2D1::Point2F(shadowTextX + font.syntheticBoldOffset(), shadowTextY), &glyphRun, shadowBrush);
}
context->DrawGlyphRun(D2D1::Point2F(point.x(), point.y()), &glyphRun, graphicsContext.solidFillBrush());
if (font.syntheticBoldOffset())
context->DrawGlyphRun(D2D1::Point2F(point.x() + font.syntheticBoldOffset(), point.y()), &glyphRun, graphicsContext.solidFillBrush());
if (hasSimpleShadow)
graphicsContext.setShadow(shadowOffset, shadowBlur, shadowColor);
graphicsContext.restore();
}
}
#endif