mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 985220: remove the old GDI, Uniscribe and DWrite text-shaping code paths, as we now use HarfBuzz or Graphite for all shaping on Windows. r=jdaggett
This commit is contained in:
parent
cb0fa693b1
commit
4216251038
@ -7,7 +7,6 @@
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include "gfxDWriteShaper.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#include <algorithm>
|
||||
#include "gfxGraphiteShaper.h"
|
||||
@ -15,8 +14,6 @@
|
||||
#include "gfxContext.h"
|
||||
#include <dwrite.h>
|
||||
|
||||
#include "gfxDWriteTextAnalysis.h"
|
||||
|
||||
#include "harfbuzz/hb.h"
|
||||
|
||||
// Chosen this as to resemble DWrite's own oblique face style.
|
||||
@ -137,10 +134,30 @@ gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
|
||||
&mStyle, mNeedsBold, anAAOption);
|
||||
}
|
||||
|
||||
void
|
||||
gfxDWriteFont::CreatePlatformShaper()
|
||||
bool
|
||||
gfxDWriteFont::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping)
|
||||
{
|
||||
mPlatformShaper = new gfxDWriteShaper(this);
|
||||
bool ok = false;
|
||||
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
|
||||
if (!ok && mHarfBuzzShaper) {
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
const gfxFont::Metrics&
|
||||
@ -595,7 +612,7 @@ gfxDWriteFont::Measure(gfxTextRun *aTextRun,
|
||||
}
|
||||
|
||||
bool
|
||||
gfxDWriteFont::ProvidesGlyphWidths()
|
||||
gfxDWriteFont::ProvidesGlyphWidths() const
|
||||
{
|
||||
return !mUseSubpixelPositions ||
|
||||
(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
gfxContext *aContextForTightBoundingBox,
|
||||
Spacing *aSpacing);
|
||||
|
||||
virtual bool ProvidesGlyphWidths();
|
||||
virtual bool ProvidesGlyphWidths() const;
|
||||
|
||||
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
|
||||
|
||||
@ -71,9 +71,13 @@ public:
|
||||
virtual cairo_scaled_font_t *GetCairoScaledFont();
|
||||
|
||||
protected:
|
||||
friend class gfxDWriteShaper;
|
||||
|
||||
virtual void CreatePlatformShaper();
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping = false);
|
||||
|
||||
bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics);
|
||||
|
||||
|
@ -1,230 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxDWriteShaper.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
|
||||
#include <dwrite.h>
|
||||
|
||||
#include "gfxDWriteTextAnalysis.h"
|
||||
|
||||
#include "nsCRT.h"
|
||||
|
||||
bool
|
||||
gfxDWriteShaper::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
HRESULT hr;
|
||||
// TODO: Handle TEXT_DISABLE_OPTIONAL_LIGATURES
|
||||
|
||||
DWRITE_READING_DIRECTION readingDirection =
|
||||
aShapedText->IsRightToLeft()
|
||||
? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
|
||||
: DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
|
||||
|
||||
gfxDWriteFont *font = static_cast<gfxDWriteFont*>(mFont);
|
||||
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
|
||||
IDWriteTextAnalyzer *analyzer =
|
||||
gfxWindowsPlatform::GetPlatform()->GetDWriteAnalyzer();
|
||||
if (!analyzer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* There's an internal 16-bit limit on some things inside the analyzer,
|
||||
* but we never attempt to shape a word longer than 32K characters
|
||||
* in a single call, so we cannot exceed that limit.
|
||||
*/
|
||||
UINT32 length = aLength;
|
||||
char16ptr_t text = aText;
|
||||
|
||||
TextAnalysis analysis(text, length, nullptr, readingDirection);
|
||||
TextAnalysis::Run *runHead;
|
||||
hr = analysis.GenerateResults(analyzer, &runHead);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Analyzer failed to generate results.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit();
|
||||
|
||||
UINT32 maxGlyphs = 0;
|
||||
trymoreglyphs:
|
||||
if ((UINT32_MAX - 3 * length / 2 + 16) < maxGlyphs) {
|
||||
// This isn't going to work, we're going to cross the UINT32 upper
|
||||
// limit. Give up.
|
||||
NS_WARNING("Shaper needs to generate more than 2^32 glyphs?!");
|
||||
return false;
|
||||
}
|
||||
maxGlyphs += 3 * length / 2 + 16;
|
||||
|
||||
AutoFallibleTArray<UINT16, 400> clusters;
|
||||
AutoFallibleTArray<UINT16, 400> indices;
|
||||
AutoFallibleTArray<DWRITE_SHAPING_TEXT_PROPERTIES, 400> textProperties;
|
||||
AutoFallibleTArray<DWRITE_SHAPING_GLYPH_PROPERTIES, 400> glyphProperties;
|
||||
if (!clusters.SetLength(length) ||
|
||||
!indices.SetLength(maxGlyphs) ||
|
||||
!textProperties.SetLength(maxGlyphs) ||
|
||||
!glyphProperties.SetLength(maxGlyphs)) {
|
||||
NS_WARNING("Shaper failed to allocate memory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT32 actualGlyphs;
|
||||
|
||||
hr = analyzer->GetGlyphs(text, length,
|
||||
font->GetFontFace(), FALSE,
|
||||
readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT,
|
||||
&runHead->mScript, nullptr, nullptr, nullptr, nullptr, 0,
|
||||
maxGlyphs, clusters.Elements(), textProperties.Elements(),
|
||||
indices.Elements(), glyphProperties.Elements(), &actualGlyphs);
|
||||
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
|
||||
// We increase the amount of glyphs and try again.
|
||||
goto trymoreglyphs;
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Analyzer failed to get glyphs.");
|
||||
return false;
|
||||
}
|
||||
|
||||
WORD gID = indices[0];
|
||||
AutoFallibleTArray<FLOAT, 400> advances;
|
||||
AutoFallibleTArray<DWRITE_GLYPH_OFFSET, 400> glyphOffsets;
|
||||
if (!advances.SetLength(actualGlyphs) ||
|
||||
!glyphOffsets.SetLength(actualGlyphs)) {
|
||||
NS_WARNING("Shaper failed to allocate memory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!static_cast<gfxDWriteFont*>(mFont)->mUseSubpixelPositions) {
|
||||
hr = analyzer->GetGdiCompatibleGlyphPlacements(
|
||||
text,
|
||||
clusters.Elements(),
|
||||
textProperties.Elements(),
|
||||
length,
|
||||
indices.Elements(),
|
||||
glyphProperties.Elements(),
|
||||
actualGlyphs,
|
||||
font->GetFontFace(),
|
||||
font->GetAdjustedSize(),
|
||||
1.0,
|
||||
nullptr,
|
||||
FALSE,
|
||||
FALSE,
|
||||
FALSE,
|
||||
&runHead->mScript,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
advances.Elements(),
|
||||
glyphOffsets.Elements());
|
||||
} else {
|
||||
hr = analyzer->GetGlyphPlacements(text,
|
||||
clusters.Elements(),
|
||||
textProperties.Elements(),
|
||||
length,
|
||||
indices.Elements(),
|
||||
glyphProperties.Elements(),
|
||||
actualGlyphs,
|
||||
font->GetFontFace(),
|
||||
font->GetAdjustedSize(),
|
||||
FALSE,
|
||||
FALSE,
|
||||
&runHead->mScript,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
advances.Elements(),
|
||||
glyphOffsets.Elements());
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Analyzer failed to get glyph placements.");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
|
||||
for (unsigned int c = 0; c < length; c++) {
|
||||
uint32_t k = clusters[c];
|
||||
uint32_t absC = aOffset + c;
|
||||
|
||||
if (c > 0 && k == clusters[c - 1]) {
|
||||
// This is a cluster continuation. No glyph here.
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[absC];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(g.IsClusterStart(), false, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Count glyphs for this character
|
||||
uint32_t glyphCount = actualGlyphs - k;
|
||||
uint32_t nextClusterOffset;
|
||||
for (nextClusterOffset = c + 1;
|
||||
nextClusterOffset < length; ++nextClusterOffset) {
|
||||
if (clusters[nextClusterOffset] > k) {
|
||||
glyphCount = clusters[nextClusterOffset] - k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int32_t advance = (int32_t)(advances[k] * appUnitsPerDevPixel);
|
||||
if (glyphCount == 1 && advance >= 0 &&
|
||||
glyphOffsets[k].advanceOffset == 0 &&
|
||||
glyphOffsets[k].ascenderOffset == 0 &&
|
||||
charGlyphs[absC].IsClusterStart() &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
|
||||
charGlyphs[absC].SetSimpleGlyph(advance, indices[k]);
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphCount) {
|
||||
if (!detailedGlyphs.AppendElements(
|
||||
glyphCount - detailedGlyphs.Length())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
float totalAdvance = 0;
|
||||
for (unsigned int z = 0; z < glyphCount; z++) {
|
||||
detailedGlyphs[z].mGlyphID = indices[k + z];
|
||||
detailedGlyphs[z].mAdvance =
|
||||
(int32_t)(advances[k + z]
|
||||
* appUnitsPerDevPixel);
|
||||
if (readingDirection ==
|
||||
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) {
|
||||
detailedGlyphs[z].mXOffset =
|
||||
(totalAdvance +
|
||||
glyphOffsets[k + z].advanceOffset)
|
||||
* appUnitsPerDevPixel;
|
||||
} else {
|
||||
detailedGlyphs[z].mXOffset =
|
||||
glyphOffsets[k + z].advanceOffset *
|
||||
appUnitsPerDevPixel;
|
||||
}
|
||||
detailedGlyphs[z].mYOffset =
|
||||
-glyphOffsets[k + z].ascenderOffset *
|
||||
appUnitsPerDevPixel;
|
||||
totalAdvance += advances[k + z];
|
||||
}
|
||||
aShapedText->SetGlyphs(
|
||||
absC,
|
||||
g.SetComplex(charGlyphs[absC].IsClusterStart(),
|
||||
true,
|
||||
glyphCount),
|
||||
detailedGlyphs.Elements());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_DWRITESHAPER_H
|
||||
#define GFX_DWRITESHAPER_H
|
||||
|
||||
#include "gfxDWriteFonts.h"
|
||||
|
||||
/**
|
||||
* \brief Class representing a DWrite font shaper.
|
||||
*/
|
||||
class gfxDWriteShaper : public gfxFontShaper
|
||||
{
|
||||
public:
|
||||
gfxDWriteShaper(gfxDWriteFont *aFont)
|
||||
: gfxFontShaper(aFont)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxDWriteShaper);
|
||||
}
|
||||
|
||||
virtual ~gfxDWriteShaper()
|
||||
{
|
||||
MOZ_COUNT_DTOR(gfxDWriteShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
};
|
||||
|
||||
#endif /* GFX_DWRITESHAPER_H */
|
@ -1,257 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxDWriteTextAnalysis.h"
|
||||
|
||||
TextAnalysis::TextAnalysis(const wchar_t* text,
|
||||
UINT32 textLength,
|
||||
const wchar_t* localeName,
|
||||
DWRITE_READING_DIRECTION readingDirection)
|
||||
: mText(text)
|
||||
, mTextLength(textLength)
|
||||
, mLocaleName(localeName)
|
||||
, mReadingDirection(readingDirection)
|
||||
, mCurrentRun(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TextAnalysis::~TextAnalysis()
|
||||
{
|
||||
// delete runs, except mRunHead which is part of the TextAnalysis object
|
||||
for (Run *run = mRunHead.nextRun; run;) {
|
||||
Run *origRun = run;
|
||||
run = run->nextRun;
|
||||
delete origRun;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
TextAnalysis::GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
|
||||
OUT Run **runHead)
|
||||
{
|
||||
// Analyzes the text using the script analyzer and returns
|
||||
// the result as a series of runs.
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
// Initially start out with one result that covers the entire range.
|
||||
// This result will be subdivided by the analysis processes.
|
||||
mRunHead.mTextStart = 0;
|
||||
mRunHead.mTextLength = mTextLength;
|
||||
mRunHead.mBidiLevel =
|
||||
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
|
||||
mRunHead.nextRun = nullptr;
|
||||
mCurrentRun = &mRunHead;
|
||||
|
||||
// Call each of the analyzers in sequence, recording their results.
|
||||
if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this,
|
||||
0,
|
||||
mTextLength,
|
||||
this))) {
|
||||
*runHead = &mRunHead;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// IDWriteTextAnalysisSource source implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::GetTextAtPosition(UINT32 textPosition,
|
||||
OUT WCHAR const** textString,
|
||||
OUT UINT32* textLength)
|
||||
{
|
||||
if (textPosition >= mTextLength) {
|
||||
// No text at this position, valid query though.
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
} else {
|
||||
*textString = mText + textPosition;
|
||||
*textLength = mTextLength - textPosition;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::GetTextBeforePosition(UINT32 textPosition,
|
||||
OUT WCHAR const** textString,
|
||||
OUT UINT32* textLength)
|
||||
{
|
||||
if (textPosition == 0 || textPosition > mTextLength) {
|
||||
// Either there is no text before here (== 0), or this
|
||||
// is an invalid position. The query is considered valid thouh.
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
} else {
|
||||
*textString = mText;
|
||||
*textLength = textPosition;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
DWRITE_READING_DIRECTION STDMETHODCALLTYPE
|
||||
TextAnalysis::GetParagraphReadingDirection()
|
||||
{
|
||||
// We support only a single reading direction.
|
||||
return mReadingDirection;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::GetLocaleName(UINT32 textPosition,
|
||||
OUT UINT32* textLength,
|
||||
OUT WCHAR const** localeName)
|
||||
{
|
||||
// Single locale name is used, valid until the end of the string.
|
||||
*localeName = mLocaleName;
|
||||
*textLength = mTextLength - textPosition;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::GetNumberSubstitution(UINT32 textPosition,
|
||||
OUT UINT32* textLength,
|
||||
OUT IDWriteNumberSubstitution** numberSubstitution)
|
||||
{
|
||||
// We do not support number substitution.
|
||||
*numberSubstitution = nullptr;
|
||||
*textLength = mTextLength - textPosition;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// IDWriteTextAnalysisSink implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::SetLineBreakpoints(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
DWRITE_LINE_BREAKPOINT const* lineBreakpoints)
|
||||
{
|
||||
// We don't use this for now.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::SetScriptAnalysis(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
|
||||
{
|
||||
SetCurrentRun(textPosition);
|
||||
SplitCurrentRun(textPosition);
|
||||
while (textLength > 0) {
|
||||
Run *run = FetchNextRun(&textLength);
|
||||
run->mScript = *scriptAnalysis;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::SetBidiLevel(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
UINT8 explicitLevel,
|
||||
UINT8 resolvedLevel)
|
||||
{
|
||||
// We don't use this for now.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::SetNumberSubstitution(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
IDWriteNumberSubstitution* numberSubstitution)
|
||||
{
|
||||
// We don't use this for now.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Run modification.
|
||||
|
||||
TextAnalysis::Run *
|
||||
TextAnalysis::FetchNextRun(IN OUT UINT32* textLength)
|
||||
{
|
||||
// Used by the sink setters, this returns a reference to the next run.
|
||||
// Position and length are adjusted to now point after the current run
|
||||
// being returned.
|
||||
|
||||
Run *origRun = mCurrentRun;
|
||||
// Split the tail if needed (the length remaining is less than the
|
||||
// current run's size).
|
||||
if (*textLength < mCurrentRun->mTextLength) {
|
||||
SplitCurrentRun(mCurrentRun->mTextStart + *textLength);
|
||||
} else {
|
||||
// Just advance the current run.
|
||||
mCurrentRun = mCurrentRun->nextRun;
|
||||
}
|
||||
*textLength -= origRun->mTextLength;
|
||||
|
||||
// Return a reference to the run that was just current.
|
||||
return origRun;
|
||||
}
|
||||
|
||||
|
||||
void TextAnalysis::SetCurrentRun(UINT32 textPosition)
|
||||
{
|
||||
// Move the current run to the given position.
|
||||
// Since the analyzers generally return results in a forward manner,
|
||||
// this will usually just return early. If not, find the
|
||||
// corresponding run for the text position.
|
||||
|
||||
if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Run *run = &mRunHead; run; run = run->nextRun) {
|
||||
if (run->ContainsTextPosition(textPosition)) {
|
||||
mCurrentRun = run;
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_NOTREACHED("We should always be able to find the text position in one \
|
||||
of our runs");
|
||||
}
|
||||
|
||||
|
||||
void TextAnalysis::SplitCurrentRun(UINT32 splitPosition)
|
||||
{
|
||||
if (!mCurrentRun) {
|
||||
NS_ASSERTION(false, "SplitCurrentRun called without current run.");
|
||||
// Shouldn't be calling this when no current run is set!
|
||||
return;
|
||||
}
|
||||
// Split the current run.
|
||||
if (splitPosition <= mCurrentRun->mTextStart) {
|
||||
// No need to split, already the start of a run
|
||||
// or before it. Usually the first.
|
||||
return;
|
||||
}
|
||||
Run *newRun = new Run;
|
||||
|
||||
*newRun = *mCurrentRun;
|
||||
|
||||
// Insert the new run in our linked list.
|
||||
newRun->nextRun = mCurrentRun->nextRun;
|
||||
mCurrentRun->nextRun = newRun;
|
||||
|
||||
// Adjust runs' text positions and lengths.
|
||||
UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart;
|
||||
newRun->mTextStart += splitPoint;
|
||||
newRun->mTextLength -= splitPoint;
|
||||
mCurrentRun->mTextLength = splitPoint;
|
||||
mCurrentRun = newRun;
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_DWRITETEXTANALYSIS_H
|
||||
#define GFX_DWRITETEXTANALYSIS_H
|
||||
|
||||
#include "gfxDWriteCommon.h"
|
||||
|
||||
// Helper source/sink class for text analysis.
|
||||
class TextAnalysis
|
||||
: public IDWriteTextAnalysisSource,
|
||||
public IDWriteTextAnalysisSink
|
||||
{
|
||||
public:
|
||||
|
||||
// IUnknown interface
|
||||
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
|
||||
{
|
||||
if (iid == __uuidof(IDWriteTextAnalysisSource)) {
|
||||
*ppObject = static_cast<IDWriteTextAnalysisSource*>(this);
|
||||
return S_OK;
|
||||
} else if (iid == __uuidof(IDWriteTextAnalysisSink)) {
|
||||
*ppObject = static_cast<IDWriteTextAnalysisSink*>(this);
|
||||
return S_OK;
|
||||
} else if (iid == __uuidof(IUnknown)) {
|
||||
*ppObject =
|
||||
static_cast<IUnknown*>(static_cast<IDWriteTextAnalysisSource*>(this));
|
||||
return S_OK;
|
||||
} else {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHOD_(ULONG, AddRef)()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
IFACEMETHOD_(ULONG, Release)()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// A single contiguous run of characters containing the same analysis
|
||||
// results.
|
||||
struct Run
|
||||
{
|
||||
UINT32 mTextStart; // starting text position of this run
|
||||
UINT32 mTextLength; // number of contiguous code units covered
|
||||
UINT32 mGlyphStart; // starting glyph in the glyphs array
|
||||
UINT32 mGlyphCount; // number of glyphs associated with this run of
|
||||
// text
|
||||
DWRITE_SCRIPT_ANALYSIS mScript;
|
||||
UINT8 mBidiLevel;
|
||||
bool mIsSideways;
|
||||
|
||||
inline bool ContainsTextPosition(UINT32 aTextPosition) const
|
||||
{
|
||||
return aTextPosition >= mTextStart
|
||||
&& aTextPosition < mTextStart + mTextLength;
|
||||
}
|
||||
|
||||
Run *nextRun;
|
||||
};
|
||||
|
||||
public:
|
||||
TextAnalysis(const wchar_t* text,
|
||||
UINT32 textLength,
|
||||
const wchar_t* localeName,
|
||||
DWRITE_READING_DIRECTION readingDirection);
|
||||
|
||||
~TextAnalysis();
|
||||
|
||||
STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
|
||||
Run **runHead);
|
||||
|
||||
// IDWriteTextAnalysisSource implementation
|
||||
|
||||
IFACEMETHODIMP GetTextAtPosition(UINT32 textPosition,
|
||||
OUT WCHAR const** textString,
|
||||
OUT UINT32* textLength);
|
||||
|
||||
IFACEMETHODIMP GetTextBeforePosition(UINT32 textPosition,
|
||||
OUT WCHAR const** textString,
|
||||
OUT UINT32* textLength);
|
||||
|
||||
IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
|
||||
GetParagraphReadingDirection() throw();
|
||||
|
||||
IFACEMETHODIMP GetLocaleName(UINT32 textPosition,
|
||||
OUT UINT32* textLength,
|
||||
OUT WCHAR const** localeName);
|
||||
|
||||
IFACEMETHODIMP
|
||||
GetNumberSubstitution(UINT32 textPosition,
|
||||
OUT UINT32* textLength,
|
||||
OUT IDWriteNumberSubstitution** numberSubstitution);
|
||||
|
||||
// IDWriteTextAnalysisSink implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetScriptAnalysis(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis);
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetLineBreakpoints(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
const DWRITE_LINE_BREAKPOINT* lineBreakpoints);
|
||||
|
||||
IFACEMETHODIMP SetBidiLevel(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
UINT8 explicitLevel,
|
||||
UINT8 resolvedLevel);
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetNumberSubstitution(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
IDWriteNumberSubstitution* numberSubstitution);
|
||||
|
||||
protected:
|
||||
Run *FetchNextRun(IN OUT UINT32* textLength);
|
||||
|
||||
void SetCurrentRun(UINT32 textPosition);
|
||||
|
||||
void SplitCurrentRun(UINT32 splitPosition);
|
||||
|
||||
protected:
|
||||
// Input
|
||||
// (weak references are fine here, since this class is a transient
|
||||
// stack-based helper that doesn't need to copy data)
|
||||
UINT32 mTextLength;
|
||||
const wchar_t* mText;
|
||||
const wchar_t* mLocaleName;
|
||||
DWRITE_READING_DIRECTION mReadingDirection;
|
||||
|
||||
// Current processing state.
|
||||
Run *mCurrentRun;
|
||||
|
||||
// Output is a list of runs starting here
|
||||
Run mRunHead;
|
||||
};
|
||||
|
||||
#endif /* GFX_DWRITETEXTANALYSIS_H */
|
@ -25,7 +25,7 @@ public:
|
||||
virtual uint32_t GetSpaceGlyph();
|
||||
virtual bool ProvidesGetGlyph() const { return true; }
|
||||
virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector);
|
||||
virtual bool ProvidesGlyphWidths() { return true; }
|
||||
virtual bool ProvidesGlyphWidths() const { return true; }
|
||||
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
|
||||
|
||||
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
|
||||
|
@ -3979,7 +3979,6 @@ gfxFont::ShapeText(gfxContext *aContext,
|
||||
if (!ok) {
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
NS_ASSERTION(mPlatformShaper, "no platform shaper available!");
|
||||
}
|
||||
if (mPlatformShaper) {
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
|
@ -1951,7 +1951,7 @@ protected:
|
||||
// subclasses may provide (possibly hinted) glyph widths (in font units);
|
||||
// if they do not override this, harfbuzz will use unhinted widths
|
||||
// derived from the font tables
|
||||
virtual bool ProvidesGlyphWidths() {
|
||||
virtual bool ProvidesGlyphWidths() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,6 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
#include "gfxGDIShaper.h"
|
||||
#include "gfxUniscribeShaper.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#include <algorithm>
|
||||
#include "gfxGraphiteShaper.h"
|
||||
@ -56,9 +54,7 @@ gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry,
|
||||
if (FontCanSupportGraphite()) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
if (FontCanSupportHarfBuzz()) {
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
|
||||
gfxGDIFont::~gfxGDIFont()
|
||||
@ -75,12 +71,6 @@ gfxGDIFont::~gfxGDIFont()
|
||||
delete mMetrics;
|
||||
}
|
||||
|
||||
void
|
||||
gfxGDIFont::CreatePlatformShaper()
|
||||
{
|
||||
mPlatformShaper = new gfxGDIShaper(this);
|
||||
}
|
||||
|
||||
gfxFont*
|
||||
gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
|
||||
{
|
||||
@ -88,29 +78,6 @@ gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
|
||||
&mStyle, mNeedsBold, anAAOption);
|
||||
}
|
||||
|
||||
static bool
|
||||
UseUniscribe(gfxShapedText *aShapedText,
|
||||
char16ptr_t aText,
|
||||
uint32_t aLength)
|
||||
{
|
||||
uint32_t flags = aShapedText->Flags();
|
||||
bool useGDI;
|
||||
|
||||
bool isXP = !IsVistaOrLater();
|
||||
|
||||
// bug 561304 - Uniscribe bug produces bad positioning at certain
|
||||
// font sizes on XP, so default to GDI on XP using logic of 3.6
|
||||
|
||||
useGDI = isXP &&
|
||||
(flags &
|
||||
(gfxTextRunFactory::TEXT_OPTIMIZE_SPEED |
|
||||
gfxTextRunFactory::TEXT_IS_RTL)
|
||||
) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
|
||||
|
||||
return !useGDI ||
|
||||
ScriptIsComplex(aText, aLength, SIC_COMPLEX) == S_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxGDIFont::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
@ -128,8 +95,6 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
|
||||
// Ensure the cairo font is set up, so there's no risk it'll fall back to
|
||||
// creating a "toy" font internally (see bug 544617).
|
||||
// We must check that this succeeded, otherwise we risk cairo creating the
|
||||
@ -138,83 +103,8 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText,
|
||||
aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
|
||||
if (!ok && mHarfBuzzShaper) {
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript) ||
|
||||
(!IsVistaOrLater() &&
|
||||
ScriptShapingType(aScript) == SHAPING_INDIC &&
|
||||
!Preferences::GetBool("gfx.font_rendering.winxp-indic-uniscribe",
|
||||
false))) {
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
|
||||
bool preferUniscribe =
|
||||
(!fe->IsTrueType() || fe->IsSymbolFont()) && !fe->mForceGDI;
|
||||
|
||||
if (preferUniscribe || UseUniscribe(aShapedText, aText, aLength)) {
|
||||
// first try Uniscribe
|
||||
if (!mUniscribeShaper) {
|
||||
mUniscribeShaper = new gfxUniscribeShaper(this);
|
||||
}
|
||||
|
||||
ok = mUniscribeShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
if (!ok) {
|
||||
// fallback to GDI shaping
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
}
|
||||
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset,
|
||||
aLength, aScript, aShapedText);
|
||||
}
|
||||
} else {
|
||||
// first use GDI
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
}
|
||||
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
if (!ok) {
|
||||
// try Uniscribe if GDI failed
|
||||
if (!mUniscribeShaper) {
|
||||
mUniscribeShaper = new gfxUniscribeShaper(this);
|
||||
}
|
||||
|
||||
// use Uniscribe shaping
|
||||
ok = mUniscribeShaper->ShapeText(aContext, aText,
|
||||
aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (!ok) {
|
||||
NS_ConvertUTF16toUTF8 name(GetName());
|
||||
char msg[256];
|
||||
|
||||
sprintf(msg,
|
||||
"text shaping with both uniscribe and GDI failed for"
|
||||
" font: %s",
|
||||
name.get());
|
||||
NS_WARNING(msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
||||
return ok;
|
||||
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
|
||||
aShapedText, aPreferPlatformShaping);
|
||||
}
|
||||
|
||||
const gfxFont::Metrics&
|
||||
@ -537,6 +427,42 @@ gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize,
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
gfxGDIFont::GetGlyph(uint32_t aUnicode, uint32_t aVarSelector)
|
||||
{
|
||||
// Callback used only for fonts that lack a 'cmap' table.
|
||||
|
||||
// We don't support variation selector sequences or non-BMP characters
|
||||
// in the legacy bitmap, vector or postscript fonts that might use
|
||||
// this code path.
|
||||
if (aUnicode > 0xffff || aVarSelector) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!mGlyphIDs) {
|
||||
mGlyphIDs = new nsDataHashtable<nsUint32HashKey,uint32_t>(128);
|
||||
}
|
||||
|
||||
uint32_t gid;
|
||||
if (mGlyphIDs->Get(aUnicode, &gid)) {
|
||||
return gid;
|
||||
}
|
||||
|
||||
AutoDC dc;
|
||||
AutoSelectFont fs(dc.GetDC(), GetHFONT());
|
||||
|
||||
wchar_t ch = aUnicode;
|
||||
WORD glyph;
|
||||
DWORD ret = GetGlyphIndicesW(dc.GetDC(), &ch, 1, &glyph,
|
||||
GGI_MARK_NONEXISTING_GLYPHS);
|
||||
if (ret == GDI_ERROR || glyph == 0xFFFF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mGlyphIDs->Put(aUnicode, glyph);
|
||||
return glyph;
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
|
||||
{
|
||||
|
@ -49,7 +49,15 @@ public:
|
||||
/* required for MathML to suppress effects of ClearType "padding" */
|
||||
virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption);
|
||||
|
||||
virtual bool ProvidesGlyphWidths() { return true; }
|
||||
// If the font has a cmap table, we handle it purely with harfbuzz;
|
||||
// but if not (e.g. .fon fonts), we'll use a GDI callback to get glyphs.
|
||||
virtual bool ProvidesGetGlyph() const {
|
||||
return !mFontEntry->HasCmapTable();
|
||||
}
|
||||
|
||||
virtual uint32_t GetGlyph(uint32_t aUnicode, uint32_t aVarSelector);
|
||||
|
||||
virtual bool ProvidesGlyphWidths() const { return true; }
|
||||
|
||||
// get hinted glyph width in pixels as 16.16 fixed-point value
|
||||
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
|
||||
@ -62,9 +70,7 @@ public:
|
||||
virtual FontType GetType() const { return FONT_TYPE_GDI; }
|
||||
|
||||
protected:
|
||||
virtual void CreatePlatformShaper();
|
||||
|
||||
/* override to check for uniscribe failure and fall back to GDI */
|
||||
/* override to ensure the cairo font is set up properly */
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
@ -80,10 +86,6 @@ protected:
|
||||
// italics.
|
||||
void FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize, bool aUseGDIFakeItalic);
|
||||
|
||||
// mPlatformShaper is used for the GDI shaper, mUniscribeShaper
|
||||
// for the Uniscribe version if needed
|
||||
nsAutoPtr<gfxFontShaper> mUniscribeShaper;
|
||||
|
||||
HFONT mFont;
|
||||
cairo_font_face_t *mFontFace;
|
||||
|
||||
@ -92,6 +94,9 @@ protected:
|
||||
|
||||
bool mNeedsBold;
|
||||
|
||||
// cache of glyph IDs (used for non-sfnt fonts only)
|
||||
nsAutoPtr<nsDataHashtable<nsUint32HashKey,uint32_t> > mGlyphIDs;
|
||||
|
||||
// cache of glyph widths in 16.16 fixed-point pixels
|
||||
nsAutoPtr<nsDataHashtable<nsUint32HashKey,int32_t> > mGlyphWidths;
|
||||
};
|
||||
|
@ -1,96 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//#define FORCE_PR_LOG
|
||||
|
||||
#include "gfxGDIShaper.h"
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* class gfxGDIShaper
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
bool
|
||||
gfxGDIShaper::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
DCFromContext dc(aContext);
|
||||
AutoSelectFont selectFont(dc, static_cast<gfxGDIFont*>(mFont)->GetHFONT());
|
||||
|
||||
uint32_t length = aLength;
|
||||
AutoFallibleTArray<WORD,500> glyphArray;
|
||||
if (!glyphArray.SetLength(length)) {
|
||||
return false;
|
||||
}
|
||||
WORD *glyphs = glyphArray.Elements();
|
||||
|
||||
DWORD ret = ::GetGlyphIndicesW(dc, char16ptr_t(aText), length,
|
||||
glyphs, GGI_MARK_NONEXISTING_GLYPHS);
|
||||
if (ret == GDI_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int k = 0; k < length; k++) {
|
||||
if (glyphs[k] == 0xFFFF)
|
||||
return false;
|
||||
}
|
||||
|
||||
SIZE size;
|
||||
AutoFallibleTArray<int,500> partialWidthArray;
|
||||
if (!partialWidthArray.SetLength(length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL success = ::GetTextExtentExPointI(dc,
|
||||
glyphs,
|
||||
length,
|
||||
INT_MAX,
|
||||
nullptr,
|
||||
partialWidthArray.Elements(),
|
||||
&size);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
gfxTextRun::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
uint32_t i;
|
||||
int32_t lastWidth = 0;
|
||||
int32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit();
|
||||
for (i = 0; i < length; ++i) {
|
||||
uint32_t offset = aOffset + i;
|
||||
int32_t advancePixels = partialWidthArray[i] - lastWidth;
|
||||
lastWidth = partialWidthArray[i];
|
||||
int32_t advanceAppUnits = advancePixels * appUnitsPerDevPixel;
|
||||
WCHAR glyph = glyphs[i];
|
||||
NS_ASSERTION(!gfxFontGroup::IsInvalidChar(aText[i]),
|
||||
"Invalid character detected!");
|
||||
bool atClusterStart = charGlyphs[offset].IsClusterStart();
|
||||
if (advanceAppUnits >= 0 &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advanceAppUnits) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(glyph) &&
|
||||
atClusterStart)
|
||||
{
|
||||
charGlyphs[offset].SetSimpleGlyph(advanceAppUnits, glyph);
|
||||
} else {
|
||||
gfxShapedText::DetailedGlyph details;
|
||||
details.mGlyphID = glyph;
|
||||
details.mAdvance = advanceAppUnits;
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
aShapedText->SetGlyphs(offset,
|
||||
g.SetComplex(atClusterStart, true, 1),
|
||||
&details);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_GDISHAPER_H
|
||||
#define GFX_GDISHAPER_H
|
||||
|
||||
#include "gfxGDIFont.h"
|
||||
|
||||
class gfxGDIShaper : public gfxFontShaper
|
||||
{
|
||||
public:
|
||||
gfxGDIShaper(gfxGDIFont *aFont)
|
||||
: gfxFontShaper(aFont)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxGDIShaper);
|
||||
}
|
||||
|
||||
virtual ~gfxGDIShaper()
|
||||
{
|
||||
MOZ_COUNT_DTOR(gfxGDIShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
};
|
||||
|
||||
#endif /* GFX_GDISHAPER_H */
|
@ -1,527 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxTypes.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxUniscribeShaper.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
|
||||
#include "gfxFontTest.h"
|
||||
|
||||
#include "cairo.h"
|
||||
#include "cairo-win32.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "prinit.h"
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* class gfxUniscribeShaper
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#define ESTIMATE_MAX_GLYPHS(L) (((3 * (L)) >> 1) + 16)
|
||||
|
||||
class UniscribeItem
|
||||
{
|
||||
public:
|
||||
UniscribeItem(gfxContext *aContext, HDC aDC,
|
||||
gfxUniscribeShaper *aShaper,
|
||||
const char16_t *aString, uint32_t aLength,
|
||||
SCRIPT_ITEM *aItem, uint32_t aIVS) :
|
||||
mContext(aContext), mDC(aDC),
|
||||
mShaper(aShaper),
|
||||
mItemString(aString), mItemLength(aLength),
|
||||
mAlternativeString(nullptr), mScriptItem(aItem),
|
||||
mScript(aItem->a.eScript),
|
||||
mNumGlyphs(0), mMaxGlyphs(ESTIMATE_MAX_GLYPHS(aLength)),
|
||||
mFontSelected(false), mIVS(aIVS)
|
||||
{
|
||||
// See bug 394751 for details.
|
||||
NS_ASSERTION(mMaxGlyphs < 65535,
|
||||
"UniscribeItem is too big, ScriptShape() will fail!");
|
||||
}
|
||||
|
||||
~UniscribeItem() {
|
||||
free(mAlternativeString);
|
||||
}
|
||||
|
||||
bool AllocateBuffers() {
|
||||
return (mGlyphs.SetLength(mMaxGlyphs) &&
|
||||
mClusters.SetLength(mItemLength + 1) &&
|
||||
mAttr.SetLength(mMaxGlyphs));
|
||||
}
|
||||
|
||||
/* possible return values:
|
||||
* S_OK - things succeeded
|
||||
* GDI_ERROR - things failed to shape. Might want to try again after calling DisableShaping()
|
||||
*/
|
||||
|
||||
HRESULT Shape() {
|
||||
HRESULT rv;
|
||||
HDC shapeDC = nullptr;
|
||||
|
||||
char16ptr_t str = mAlternativeString ? mAlternativeString : mItemString;
|
||||
|
||||
mScriptItem->a.fLogicalOrder = true;
|
||||
SCRIPT_ANALYSIS sa = mScriptItem->a;
|
||||
|
||||
while (true) {
|
||||
|
||||
rv = ScriptShape(shapeDC, mShaper->ScriptCache(),
|
||||
str, mItemLength,
|
||||
mMaxGlyphs, &sa,
|
||||
mGlyphs.Elements(), mClusters.Elements(),
|
||||
mAttr.Elements(), &mNumGlyphs);
|
||||
|
||||
if (rv == E_OUTOFMEMORY) {
|
||||
mMaxGlyphs *= 2;
|
||||
if (!mGlyphs.SetLength(mMaxGlyphs) ||
|
||||
!mAttr.SetLength(mMaxGlyphs)) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Uniscribe can't do shaping with some fonts, so it sets the
|
||||
// fNoGlyphIndex flag in the SCRIPT_ANALYSIS structure to indicate
|
||||
// this. This occurs with CFF fonts loaded with
|
||||
// AddFontMemResourceEx but it's not clear what the other cases
|
||||
// are. We return an error so our caller can try fallback shaping.
|
||||
// see http://msdn.microsoft.com/en-us/library/ms776520(VS.85).aspx
|
||||
|
||||
if (sa.fNoGlyphIndex) {
|
||||
return GDI_ERROR;
|
||||
}
|
||||
|
||||
if (rv == E_PENDING) {
|
||||
if (shapeDC == mDC) {
|
||||
// we already tried this once, something failed, give up
|
||||
return E_PENDING;
|
||||
}
|
||||
|
||||
SelectFont();
|
||||
|
||||
shapeDC = mDC;
|
||||
continue;
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/dd368564(VS.85).aspx:
|
||||
// Uniscribe will return this if "the font corresponding to the
|
||||
// DC does not support the script required by the run...".
|
||||
// In this case, we'll set the script code to SCRIPT_UNDEFINED
|
||||
// and try again, so that we'll at least get glyphs even though
|
||||
// they won't necessarily have proper shaping.
|
||||
// (We probably shouldn't have selected this font at all,
|
||||
// but it's too late to fix that here.)
|
||||
if (rv == USP_E_SCRIPT_NOT_IN_FONT) {
|
||||
sa.eScript = SCRIPT_UNDEFINED;
|
||||
NS_WARNING("Uniscribe says font does not support script needed");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prior to Windows 7, Uniscribe didn't support Ideographic Variation
|
||||
// Selectors. Replace the UVS glyph manually.
|
||||
if (mIVS) {
|
||||
uint32_t lastChar = str[mItemLength - 1];
|
||||
if (NS_IS_LOW_SURROGATE(lastChar)
|
||||
&& NS_IS_HIGH_SURROGATE(str[mItemLength - 2])) {
|
||||
lastChar = SURROGATE_TO_UCS4(str[mItemLength - 2], lastChar);
|
||||
}
|
||||
uint16_t glyphId = mShaper->GetFont()->GetUVSGlyph(lastChar, mIVS);
|
||||
if (glyphId) {
|
||||
mGlyphs[mNumGlyphs - 1] = glyphId;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShapingEnabled() {
|
||||
return (mScriptItem->a.eScript != SCRIPT_UNDEFINED);
|
||||
}
|
||||
void DisableShaping() {
|
||||
mScriptItem->a.eScript = SCRIPT_UNDEFINED;
|
||||
// Note: If we disable the shaping by using SCRIPT_UNDEFINED and
|
||||
// the string has the surrogate pair, ScriptShape API is
|
||||
// *sometimes* crashed. Therefore, we should replace the surrogate
|
||||
// pair to U+FFFD. See bug 341500.
|
||||
GenerateAlternativeString();
|
||||
}
|
||||
void EnableShaping() {
|
||||
mScriptItem->a.eScript = mScript;
|
||||
if (mAlternativeString) {
|
||||
free(mAlternativeString);
|
||||
mAlternativeString = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsGlyphMissing(SCRIPT_FONTPROPERTIES *aSFP, uint32_t aGlyphIndex) {
|
||||
return (mGlyphs[aGlyphIndex] == aSFP->wgDefault);
|
||||
}
|
||||
|
||||
|
||||
HRESULT Place() {
|
||||
HRESULT rv;
|
||||
HDC placeDC = nullptr;
|
||||
|
||||
if (!mOffsets.SetLength(mNumGlyphs) ||
|
||||
!mAdvances.SetLength(mNumGlyphs)) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
SCRIPT_ANALYSIS sa = mScriptItem->a;
|
||||
|
||||
while (true) {
|
||||
rv = ScriptPlace(placeDC, mShaper->ScriptCache(),
|
||||
mGlyphs.Elements(), mNumGlyphs,
|
||||
mAttr.Elements(), &sa,
|
||||
mAdvances.Elements(), mOffsets.Elements(), nullptr);
|
||||
|
||||
if (rv == E_PENDING) {
|
||||
SelectFont();
|
||||
placeDC = mDC;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rv == USP_E_SCRIPT_NOT_IN_FONT) {
|
||||
sa.eScript = SCRIPT_UNDEFINED;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void ScriptFontProperties(SCRIPT_FONTPROPERTIES *sfp) {
|
||||
HRESULT rv;
|
||||
|
||||
memset(sfp, 0, sizeof(SCRIPT_FONTPROPERTIES));
|
||||
sfp->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
|
||||
rv = ScriptGetFontProperties(nullptr, mShaper->ScriptCache(),
|
||||
sfp);
|
||||
if (rv == E_PENDING) {
|
||||
SelectFont();
|
||||
rv = ScriptGetFontProperties(mDC, mShaper->ScriptCache(),
|
||||
sfp);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveGlyphs(gfxShapedText *aShapedText, uint32_t aOffset) {
|
||||
uint32_t offsetInRun = mScriptItem->iCharPos;
|
||||
|
||||
// XXX We should store this in the item and only fetch it once
|
||||
SCRIPT_FONTPROPERTIES sfp;
|
||||
ScriptFontProperties(&sfp);
|
||||
|
||||
uint32_t offset = 0;
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
while (offset < mItemLength) {
|
||||
uint32_t runOffset = aOffset + offsetInRun + offset;
|
||||
bool atClusterStart = charGlyphs[runOffset].IsClusterStart();
|
||||
if (offset > 0 && mClusters[offset] == mClusters[offset - 1]) {
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[runOffset];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(atClusterStart, false, 0);
|
||||
} else {
|
||||
// Count glyphs for this character
|
||||
uint32_t k = mClusters[offset];
|
||||
uint32_t glyphCount = mNumGlyphs - k;
|
||||
uint32_t nextClusterOffset;
|
||||
bool missing = IsGlyphMissing(&sfp, k);
|
||||
for (nextClusterOffset = offset + 1; nextClusterOffset < mItemLength; ++nextClusterOffset) {
|
||||
if (mClusters[nextClusterOffset] > k) {
|
||||
glyphCount = mClusters[nextClusterOffset] - k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint32_t j;
|
||||
for (j = 1; j < glyphCount; ++j) {
|
||||
if (IsGlyphMissing(&sfp, k + j)) {
|
||||
missing = true;
|
||||
}
|
||||
}
|
||||
int32_t advance = mAdvances[k]*appUnitsPerDevUnit;
|
||||
WORD glyph = mGlyphs[k];
|
||||
NS_ASSERTION(!gfxFontGroup::IsInvalidChar(mItemString[offset]),
|
||||
"invalid character detected");
|
||||
if (missing) {
|
||||
if (NS_IS_HIGH_SURROGATE(mItemString[offset]) &&
|
||||
offset + 1 < mItemLength &&
|
||||
NS_IS_LOW_SURROGATE(mItemString[offset + 1])) {
|
||||
aShapedText->SetMissingGlyph(runOffset,
|
||||
SURROGATE_TO_UCS4(mItemString[offset],
|
||||
mItemString[offset + 1]),
|
||||
mShaper->GetFont());
|
||||
} else {
|
||||
aShapedText->SetMissingGlyph(runOffset, mItemString[offset],
|
||||
mShaper->GetFont());
|
||||
}
|
||||
} else if (glyphCount == 1 && advance >= 0 &&
|
||||
mOffsets[k].dv == 0 && mOffsets[k].du == 0 &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(glyph) &&
|
||||
atClusterStart)
|
||||
{
|
||||
charGlyphs[runOffset].SetSimpleGlyph(advance, glyph);
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphCount) {
|
||||
if (!detailedGlyphs.AppendElements(glyphCount - detailedGlyphs.Length()))
|
||||
return;
|
||||
}
|
||||
uint32_t i;
|
||||
for (i = 0; i < glyphCount; ++i) {
|
||||
gfxTextRun::DetailedGlyph *details = &detailedGlyphs[i];
|
||||
details->mGlyphID = mGlyphs[k + i];
|
||||
details->mAdvance = mAdvances[k + i] * appUnitsPerDevUnit;
|
||||
details->mXOffset = float(mOffsets[k + i].du) * appUnitsPerDevUnit *
|
||||
aShapedText->GetDirection();
|
||||
details->mYOffset = - float(mOffsets[k + i].dv) * appUnitsPerDevUnit;
|
||||
}
|
||||
aShapedText->SetGlyphs(runOffset,
|
||||
g.SetComplex(atClusterStart, true,
|
||||
glyphCount),
|
||||
detailedGlyphs.Elements());
|
||||
}
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
|
||||
void SelectFont() {
|
||||
if (mFontSelected)
|
||||
return;
|
||||
|
||||
cairo_t *cr = mContext->GetCairo();
|
||||
|
||||
cairo_set_font_face(cr, mShaper->GetFont()->CairoFontFace());
|
||||
cairo_set_font_size(cr, mShaper->GetFont()->GetAdjustedSize());
|
||||
cairo_scaled_font_t *scaledFont = mShaper->GetFont()->CairoScaledFont();
|
||||
cairo_win32_scaled_font_select_font(scaledFont, mDC);
|
||||
|
||||
mFontSelected = true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void GenerateAlternativeString() {
|
||||
if (mAlternativeString)
|
||||
free(mAlternativeString);
|
||||
mAlternativeString = (char16_t *)malloc(mItemLength * sizeof(char16_t));
|
||||
if (!mAlternativeString)
|
||||
return;
|
||||
memcpy((void *)mAlternativeString, (const void *)mItemString,
|
||||
mItemLength * sizeof(char16_t));
|
||||
for (uint32_t i = 0; i < mItemLength; i++) {
|
||||
if (NS_IS_HIGH_SURROGATE(mItemString[i]) || NS_IS_LOW_SURROGATE(mItemString[i]))
|
||||
mAlternativeString[i] = char16_t(0xFFFD);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<gfxContext> mContext;
|
||||
HDC mDC;
|
||||
gfxUniscribeShaper *mShaper;
|
||||
|
||||
SCRIPT_ITEM *mScriptItem;
|
||||
WORD mScript;
|
||||
|
||||
public:
|
||||
// these point to the full string/length of the item
|
||||
const char16_t *mItemString;
|
||||
const uint32_t mItemLength;
|
||||
|
||||
private:
|
||||
char16_t *mAlternativeString;
|
||||
|
||||
#define AVERAGE_ITEM_LENGTH 40
|
||||
|
||||
AutoFallibleTArray<WORD, uint32_t(ESTIMATE_MAX_GLYPHS(AVERAGE_ITEM_LENGTH))> mGlyphs;
|
||||
AutoFallibleTArray<WORD, AVERAGE_ITEM_LENGTH + 1> mClusters;
|
||||
AutoFallibleTArray<SCRIPT_VISATTR, uint32_t(ESTIMATE_MAX_GLYPHS(AVERAGE_ITEM_LENGTH))> mAttr;
|
||||
|
||||
AutoFallibleTArray<GOFFSET, 2 * AVERAGE_ITEM_LENGTH> mOffsets;
|
||||
AutoFallibleTArray<int, 2 * AVERAGE_ITEM_LENGTH> mAdvances;
|
||||
|
||||
#undef AVERAGE_ITEM_LENGTH
|
||||
|
||||
int mMaxGlyphs;
|
||||
int mNumGlyphs;
|
||||
uint32_t mIVS;
|
||||
|
||||
bool mFontSelected;
|
||||
};
|
||||
|
||||
class Uniscribe
|
||||
{
|
||||
public:
|
||||
Uniscribe(const char16_t *aString,
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset, uint32_t aLength):
|
||||
mString(aString), mShapedText(aShapedText),
|
||||
mOffset(aOffset), mLength(aLength)
|
||||
{
|
||||
}
|
||||
|
||||
void Init() {
|
||||
memset(&mControl, 0, sizeof(SCRIPT_CONTROL));
|
||||
memset(&mState, 0, sizeof(SCRIPT_STATE));
|
||||
// Lock the direction. Don't allow the itemizer to change directions
|
||||
// based on character type.
|
||||
mState.uBidiLevel = mShapedText->IsRightToLeft() ? 1 : 0;
|
||||
mState.fOverrideDirection = true;
|
||||
}
|
||||
|
||||
public:
|
||||
int Itemize() {
|
||||
HRESULT rv;
|
||||
|
||||
int maxItems = 5;
|
||||
|
||||
Init();
|
||||
|
||||
// Allocate space for one more item than expected, to handle a rare
|
||||
// overflow in ScriptItemize (pre XP SP2). See bug 366643.
|
||||
if (!mItems.SetLength(maxItems + 1)) {
|
||||
return 0;
|
||||
}
|
||||
while ((rv = ScriptItemize(mString, mLength,
|
||||
maxItems, &mControl, &mState,
|
||||
mItems.Elements(), &mNumItems)) == E_OUTOFMEMORY) {
|
||||
maxItems *= 2;
|
||||
if (!mItems.SetLength(maxItems + 1)) {
|
||||
return 0;
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
return mNumItems;
|
||||
}
|
||||
|
||||
SCRIPT_ITEM *ScriptItem(uint32_t i) {
|
||||
NS_ASSERTION(i <= (uint32_t)mNumItems, "Trying to get out of bounds item");
|
||||
return &mItems[i];
|
||||
}
|
||||
|
||||
private:
|
||||
char16ptr_t mString;
|
||||
gfxShapedText *mShapedText;
|
||||
uint32_t mOffset;
|
||||
uint32_t mLength;
|
||||
|
||||
SCRIPT_CONTROL mControl;
|
||||
SCRIPT_STATE mState;
|
||||
FallibleTArray<SCRIPT_ITEM> mItems;
|
||||
int mNumItems;
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
gfxUniscribeShaper::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
DCFromContext aDC(aContext);
|
||||
|
||||
bool result = true;
|
||||
HRESULT rv;
|
||||
|
||||
Uniscribe us(aText, aShapedText, aOffset, aLength);
|
||||
|
||||
/* itemize the string */
|
||||
int numItems = us.Itemize();
|
||||
|
||||
uint32_t length = aLength;
|
||||
SaveDC(aDC);
|
||||
uint32_t ivs = 0;
|
||||
for (int i = 0; i < numItems; ++i) {
|
||||
int iCharPos = us.ScriptItem(i)->iCharPos;
|
||||
int iCharPosNext = us.ScriptItem(i+1)->iCharPos;
|
||||
|
||||
if (ivs) {
|
||||
iCharPos += 2;
|
||||
if (iCharPos >= iCharPosNext) {
|
||||
ivs = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (i+1 < numItems && iCharPosNext <= length - 2
|
||||
&& aText[iCharPosNext] == H_SURROGATE(kUnicodeVS17)
|
||||
&& uint32_t(aText[iCharPosNext + 1]) - L_SURROGATE(kUnicodeVS17)
|
||||
<= L_SURROGATE(kUnicodeVS256) - L_SURROGATE(kUnicodeVS17)) {
|
||||
|
||||
ivs = SURROGATE_TO_UCS4(aText[iCharPosNext],
|
||||
aText[iCharPosNext + 1]);
|
||||
} else {
|
||||
ivs = 0;
|
||||
}
|
||||
|
||||
UniscribeItem item(aContext, aDC, this,
|
||||
aText + iCharPos,
|
||||
iCharPosNext - iCharPos,
|
||||
us.ScriptItem(i), ivs);
|
||||
if (!item.AllocateBuffers()) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!item.ShapingEnabled()) {
|
||||
item.EnableShaping();
|
||||
}
|
||||
|
||||
rv = item.Shape();
|
||||
if (FAILED(rv)) {
|
||||
// we know we have the glyphs to display this font already
|
||||
// so Uniscribe just doesn't know how to shape the script.
|
||||
// Render the glyphs without shaping.
|
||||
item.DisableShaping();
|
||||
rv = item.Shape();
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (FAILED(rv)) {
|
||||
NS_WARNING("Uniscribe failed to shape with font");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SUCCEEDED(rv)) {
|
||||
rv = item.Place();
|
||||
#ifdef DEBUG
|
||||
if (FAILED(rv)) {
|
||||
// crap fonts may fail when placing (e.g. funky free fonts)
|
||||
NS_WARNING("Uniscribe failed to place with font");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (FAILED(rv)) {
|
||||
// Uniscribe doesn't like this font for some reason.
|
||||
// Returning FALSE will make the gfxGDIFont retry with the
|
||||
// "dumb" GDI shaper, unless useUniscribeOnly was set.
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
item.SaveGlyphs(aShapedText, aOffset);
|
||||
}
|
||||
|
||||
RestoreDC(aDC, -1);
|
||||
|
||||
return result;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_UNISCRIBESHAPER_H
|
||||
#define GFX_UNISCRIBESHAPER_H
|
||||
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxGDIFont.h"
|
||||
|
||||
#include <usp10.h>
|
||||
#include <cairo-win32.h>
|
||||
|
||||
|
||||
class gfxUniscribeShaper : public gfxFontShaper
|
||||
{
|
||||
public:
|
||||
gfxUniscribeShaper(gfxGDIFont *aFont)
|
||||
: gfxFontShaper(aFont)
|
||||
, mScriptCache(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxUniscribeShaper);
|
||||
}
|
||||
|
||||
virtual ~gfxUniscribeShaper()
|
||||
{
|
||||
MOZ_COUNT_DTOR(gfxUniscribeShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
SCRIPT_CACHE *ScriptCache() { return &mScriptCache; }
|
||||
|
||||
gfxGDIFont *GetFont() { return static_cast<gfxGDIFont*>(mFont); }
|
||||
|
||||
private:
|
||||
SCRIPT_CACHE mScriptCache;
|
||||
|
||||
enum {
|
||||
kUnicodeVS17 = gfxFontUtils::kUnicodeVS17,
|
||||
kUnicodeVS256 = gfxFontUtils::kUnicodeVS256
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* GFX_UNISCRIBESHAPER_H */
|
@ -170,13 +170,11 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
'gfxWindowsPlatform.h',
|
||||
'gfxWindowsSurface.h',
|
||||
]
|
||||
# gfxGDIFontList.cpp and gfxGDIShaper.cpp force NSPR logging, so they cannot be built in unified mode.
|
||||
# gfxGDIFontList.cpp forces NSPR logging, so it cannot be built in unified mode.
|
||||
SOURCES += [
|
||||
'gfxGDIFont.cpp',
|
||||
'gfxGDIFontList.cpp',
|
||||
'gfxGDIShaper.cpp',
|
||||
'gfxPDFSurface.cpp',
|
||||
'gfxUniscribeShaper.cpp',
|
||||
'gfxWindowsNativeDrawing.cpp',
|
||||
'gfxWindowsPlatform.cpp',
|
||||
'gfxWindowsSurface.cpp',
|
||||
@ -188,8 +186,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
'gfxDWriteCommon.cpp',
|
||||
'gfxDWriteFontList.cpp',
|
||||
'gfxDWriteFonts.cpp',
|
||||
'gfxDWriteShaper.cpp',
|
||||
'gfxDWriteTextAnalysis.cpp',
|
||||
]
|
||||
|
||||
# Are we targeting x86 or x64? If so, build gfxAlphaRecoverySSE2.cpp.
|
||||
|
Loading…
Reference in New Issue
Block a user