From 088699795b2575b38cb67997ede4e766ce420f55 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Mon, 9 Jun 2014 15:47:31 +0100 Subject: [PATCH] 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 --- gfx/thebes/gfxDWriteFonts.cpp | 31 +- gfx/thebes/gfxDWriteFonts.h | 12 +- gfx/thebes/gfxDWriteShaper.cpp | 230 ------------ gfx/thebes/gfxDWriteShaper.h | 36 -- gfx/thebes/gfxDWriteTextAnalysis.cpp | 257 ------------- gfx/thebes/gfxDWriteTextAnalysis.h | 146 -------- gfx/thebes/gfxFT2FontBase.h | 2 +- gfx/thebes/gfxFont.cpp | 1 - gfx/thebes/gfxFont.h | 2 +- gfx/thebes/gfxGDIFont.cpp | 152 ++------ gfx/thebes/gfxGDIFont.h | 21 +- gfx/thebes/gfxGDIShaper.cpp | 96 ----- gfx/thebes/gfxGDIShaper.h | 33 -- gfx/thebes/gfxUniscribeShaper.cpp | 527 --------------------------- gfx/thebes/gfxUniscribeShaper.h | 51 --- gfx/thebes/moz.build | 6 +- 16 files changed, 87 insertions(+), 1516 deletions(-) delete mode 100644 gfx/thebes/gfxDWriteShaper.cpp delete mode 100644 gfx/thebes/gfxDWriteShaper.h delete mode 100644 gfx/thebes/gfxDWriteTextAnalysis.cpp delete mode 100644 gfx/thebes/gfxDWriteTextAnalysis.h delete mode 100644 gfx/thebes/gfxGDIShaper.cpp delete mode 100644 gfx/thebes/gfxGDIShaper.h delete mode 100644 gfx/thebes/gfxUniscribeShaper.cpp delete mode 100644 gfx/thebes/gfxUniscribeShaper.h diff --git a/gfx/thebes/gfxDWriteFonts.cpp b/gfx/thebes/gfxDWriteFonts.cpp index de2e16d9f0af..38c16bdd6640 100644 --- a/gfx/thebes/gfxDWriteFonts.cpp +++ b/gfx/thebes/gfxDWriteFonts.cpp @@ -7,7 +7,6 @@ #include "mozilla/MemoryReporting.h" -#include "gfxDWriteShaper.h" #include "gfxHarfBuzzShaper.h" #include #include "gfxGraphiteShaper.h" @@ -15,8 +14,6 @@ #include "gfxContext.h" #include -#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); diff --git a/gfx/thebes/gfxDWriteFonts.h b/gfx/thebes/gfxDWriteFonts.h index da0ebcb4125f..8ee972b553d3 100644 --- a/gfx/thebes/gfxDWriteFonts.h +++ b/gfx/thebes/gfxDWriteFonts.h @@ -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); diff --git a/gfx/thebes/gfxDWriteShaper.cpp b/gfx/thebes/gfxDWriteShaper.cpp deleted file mode 100644 index 4526d28f315b..000000000000 --- a/gfx/thebes/gfxDWriteShaper.cpp +++ /dev/null @@ -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 - -#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(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 clusters; - AutoFallibleTArray indices; - AutoFallibleTArray textProperties; - AutoFallibleTArray 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 advances; - AutoFallibleTArray glyphOffsets; - if (!advances.SetLength(actualGlyphs) || - !glyphOffsets.SetLength(actualGlyphs)) { - NS_WARNING("Shaper failed to allocate memory."); - return false; - } - - if (!static_cast(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 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; -} diff --git a/gfx/thebes/gfxDWriteShaper.h b/gfx/thebes/gfxDWriteShaper.h deleted file mode 100644 index 03072f8be975..000000000000 --- a/gfx/thebes/gfxDWriteShaper.h +++ /dev/null @@ -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 */ diff --git a/gfx/thebes/gfxDWriteTextAnalysis.cpp b/gfx/thebes/gfxDWriteTextAnalysis.cpp deleted file mode 100644 index fc97f05939de..000000000000 --- a/gfx/thebes/gfxDWriteTextAnalysis.cpp +++ /dev/null @@ -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; -} diff --git a/gfx/thebes/gfxDWriteTextAnalysis.h b/gfx/thebes/gfxDWriteTextAnalysis.h deleted file mode 100644 index 974f16ce47d8..000000000000 --- a/gfx/thebes/gfxDWriteTextAnalysis.h +++ /dev/null @@ -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(this); - return S_OK; - } else if (iid == __uuidof(IDWriteTextAnalysisSink)) { - *ppObject = static_cast(this); - return S_OK; - } else if (iid == __uuidof(IUnknown)) { - *ppObject = - static_cast(static_cast(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 */ diff --git a/gfx/thebes/gfxFT2FontBase.h b/gfx/thebes/gfxFT2FontBase.h index 1061339dc8de..58bc60661bae 100644 --- a/gfx/thebes/gfxFT2FontBase.h +++ b/gfx/thebes/gfxFT2FontBase.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; }; diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 114017cc0297..88b12e88e521 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -3983,7 +3983,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, diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index dfbcdcb81344..36b144587e34 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -1952,7 +1952,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; } diff --git a/gfx/thebes/gfxGDIFont.cpp b/gfx/thebes/gfxGDIFont.cpp index 2d6b1d8e6c52..a410ff974bd7 100644 --- a/gfx/thebes/gfxGDIFont.cpp +++ b/gfx/thebes/gfxGDIFont.cpp @@ -8,8 +8,6 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/WindowsVersion.h" -#include "gfxGDIShaper.h" -#include "gfxUniscribeShaper.h" #include "gfxHarfBuzzShaper.h" #include #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(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(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) { diff --git a/gfx/thebes/gfxGDIFont.h b/gfx/thebes/gfxGDIFont.h index 4ce3854944bf..3b979c41387b 100644 --- a/gfx/thebes/gfxGDIFont.h +++ b/gfx/thebes/gfxGDIFont.h @@ -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 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 > mGlyphIDs; + // cache of glyph widths in 16.16 fixed-point pixels nsAutoPtr > mGlyphWidths; }; diff --git a/gfx/thebes/gfxGDIShaper.cpp b/gfx/thebes/gfxGDIShaper.cpp deleted file mode 100644 index f38cd8f66b6f..000000000000 --- a/gfx/thebes/gfxGDIShaper.cpp +++ /dev/null @@ -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(mFont)->GetHFONT()); - - uint32_t length = aLength; - AutoFallibleTArray 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 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; -} diff --git a/gfx/thebes/gfxGDIShaper.h b/gfx/thebes/gfxGDIShaper.h deleted file mode 100644 index 0bfc812b5be3..000000000000 --- a/gfx/thebes/gfxGDIShaper.h +++ /dev/null @@ -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 */ diff --git a/gfx/thebes/gfxUniscribeShaper.cpp b/gfx/thebes/gfxUniscribeShaper.cpp deleted file mode 100644 index 2e16be22665a..000000000000 --- a/gfx/thebes/gfxUniscribeShaper.cpp +++ /dev/null @@ -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 - -#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 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 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 mGlyphs; - AutoFallibleTArray mClusters; - AutoFallibleTArray mAttr; - - AutoFallibleTArray mOffsets; - AutoFallibleTArray 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 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; -} diff --git a/gfx/thebes/gfxUniscribeShaper.h b/gfx/thebes/gfxUniscribeShaper.h deleted file mode 100644 index a694b5961edd..000000000000 --- a/gfx/thebes/gfxUniscribeShaper.h +++ /dev/null @@ -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 -#include - - -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(mFont); } - -private: - SCRIPT_CACHE mScriptCache; - - enum { - kUnicodeVS17 = gfxFontUtils::kUnicodeVS17, - kUnicodeVS256 = gfxFontUtils::kUnicodeVS256 - }; -}; - -#endif /* GFX_UNISCRIBESHAPER_H */ diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index a207bb976fba..e04933a44491 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -171,13 +171,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', @@ -189,8 +187,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.