blob: f067a40eae9e6f7d55436682c87c1bf6f4bd6b1f [file] [log] [blame]
/*
* Copyright (C) 2012, 2013 Research In Motion Limited. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "Font.h"
#include "AffineTransform.h"
#include "FloatPoint.h"
#include "FloatRect.h"
#include "FontCache.h"
#include "GlyphBuffer.h"
#include "GraphicsContext.h"
#include "HarfBuzzShaper.h"
#include "ShadowBlur.h"
#include "TextRun.h"
#include <BlackBerryPlatformGraphicsContext.h>
#include <fs_api.h>
#include <wtf/MathExtras.h>
static inline float FSFixedToFloat(FS_FIXED n) { return n / 65536.0; }
static inline FS_FIXED FloatToFSFixed(float n) { return static_cast<FS_FIXED>(n * 65536); }
namespace WebCore {
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
if (!run.length())
return;
GlyphBuffer glyphBuffer;
HarfBuzzShaper shaper(this, run);
shaper.setDrawRange(from, to);
if (!shaper.shape(&glyphBuffer))
return;
FloatPoint adjustedPoint = shaper.adjustStartPoint(point);
drawGlyphBuffer(context, run, glyphBuffer, adjustedPoint);
}
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
{
HarfBuzzShaper shaper(this, run);
if (!shaper.shape())
return 0;
return shaper.totalWidth();
}
// Return the code point index for the given |x| offset into the text run.
int Font::offsetForPositionForComplexText(const TextRun& run, float position, bool includePartialGlyphs) const
{
// FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
// to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
int targetX = static_cast<int>(position);
HarfBuzzShaper shaper(this, run);
if (!shaper.shape())
return 0;
return shaper.offsetForPosition(targetX);
}
FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int height, int from, int to) const
{
HarfBuzzShaper shaper(this, run);
if (!shaper.shape())
return FloatRect();
return shaper.selectionRect(point, height, from, to);
}
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
{
FS_STATE* iType = font->platformData().scaledFont(context->getCTM().yScale());
if (!iType)
return;
FloatPoint adjustedPoint = point;
if (font->platformData().orientation() == Vertical)
adjustedPoint.move(-(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent()), 0);
bool softwareBlurRequired = context->state().shadowBlur / font->fontMetrics().xHeight() > 0.5;
FloatSize currentShadowOffset;
float currentShadowBlur;
Color currentShadowColor;
ColorSpace currentColorSpace;
// If we have a shadow blur, and it is too big to apply at text-render time, we must render it now.
if (context->hasShadow() && softwareBlurRequired) {
context->getShadow(currentShadowOffset, currentShadowBlur, currentShadowColor, currentColorSpace);
const GraphicsContextState state = context->state();
FloatSize offset = state.shadowOffset;
if (state.shadowsIgnoreTransforms)
offset.setHeight(-offset.height());
ShadowBlur shadow(FloatSize(state.shadowBlur, state.shadowBlur), offset, state.shadowColor, state.shadowColorSpace);
FloatPoint minPoint(adjustedPoint.x(), adjustedPoint.y() - fontMetrics().ascent());
FloatPoint maxPoint(adjustedPoint.x(), adjustedPoint.y() + fontMetrics().descent());
FloatPoint currentPoint = adjustedPoint;
for (int i = 0; i < numGlyphs; ++i) {
currentPoint += *glyphBuffer.advances(from + i);
minPoint.setX(std::min(minPoint.x(), currentPoint.x()));
minPoint.setY(std::min(minPoint.y(), currentPoint.y()));
maxPoint = maxPoint.expandedTo(currentPoint);
}
const FloatRect boundingRect(minPoint.x(), minPoint.y(), maxPoint.x() - minPoint.x(), maxPoint.y() - minPoint.y());
GraphicsContext* shadowContext = shadow.beginShadowLayer(context, boundingRect);
if (shadowContext) {
iType = font->platformData().scaledFont(shadowContext->getCTM().yScale());
shadowContext->platformContext()->addGlyphs(glyphBuffer.glyphs(from),
reinterpret_cast<const BlackBerry::Platform::FloatSize*>(glyphBuffer.advances(from)),
numGlyphs, adjustedPoint, iType, 0, 0);
iType = font->platformData().scaledFont(context->getCTM().yScale());
shadow.endShadowLayer(context);
}
context->platformContext()->clearShadow();
}
context->platformContext()->addGlyphs(glyphBuffer.glyphs(from),
reinterpret_cast<const BlackBerry::Platform::FloatSize*>(glyphBuffer.advances(from)),
numGlyphs, adjustedPoint, iType,
context->fillGradient() ? context->fillGradient()->platformGradient() : (context->fillPattern() ? context->fillPattern()->platformPattern(AffineTransform()) : static_cast<BlackBerry::Platform::Graphics::Paint*>(0)),
context->strokeGradient() ? context->strokeGradient()->platformGradient() : (context->strokePattern() ? context->strokePattern()->platformPattern(AffineTransform()) : static_cast<BlackBerry::Platform::Graphics::Paint*>(0)));
if (softwareBlurRequired)
context->platformContext()->setShadow(currentShadowOffset, currentShadowBlur, currentShadowColor.isValid() ? currentShadowColor.rgb() : makeRGBA(0, 0, 0, 0xFF / 3), context->state().shadowsIgnoreTransforms);
}
bool Font::canReturnFallbackFontsForComplexText()
{
return false;
}
void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
{
// notImplemented();
}
bool Font::canExpandAroundIdeographsInComplexText()
{
return false;
}
}