gfx/thebes/gfxDWriteTextAnalysis.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "gfxDWriteTextAnalysis.h"
     8 TextAnalysis::TextAnalysis(const wchar_t* text,
     9                            UINT32 textLength,
    10                            const wchar_t* localeName,
    11                            DWRITE_READING_DIRECTION readingDirection)
    12   : mText(text)
    13   , mTextLength(textLength)
    14   , mLocaleName(localeName)
    15   , mReadingDirection(readingDirection)
    16   , mCurrentRun(nullptr)
    17 {
    18 }
    20 TextAnalysis::~TextAnalysis()
    21 {
    22     // delete runs, except mRunHead which is part of the TextAnalysis object
    23     for (Run *run = mRunHead.nextRun; run;) {
    24         Run *origRun = run;
    25         run = run->nextRun;
    26         delete origRun;
    27     }
    28 }
    30 STDMETHODIMP 
    31 TextAnalysis::GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
    32                               OUT Run **runHead)
    33 {
    34     // Analyzes the text using the script analyzer and returns
    35     // the result as a series of runs.
    37     HRESULT hr = S_OK;
    39     // Initially start out with one result that covers the entire range.
    40     // This result will be subdivided by the analysis processes.
    41     mRunHead.mTextStart = 0;
    42     mRunHead.mTextLength = mTextLength;
    43     mRunHead.mBidiLevel = 
    44         (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
    45     mRunHead.nextRun = nullptr;
    46     mCurrentRun = &mRunHead;
    48     // Call each of the analyzers in sequence, recording their results.
    49     if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this,
    50                                                    0,
    51                                                    mTextLength,
    52                                                    this))) {
    53         *runHead = &mRunHead;
    54     }
    56     return hr;
    57 }
    60 ////////////////////////////////////////////////////////////////////////////////
    61 // IDWriteTextAnalysisSource source implementation
    63 IFACEMETHODIMP 
    64 TextAnalysis::GetTextAtPosition(UINT32 textPosition,
    65                                 OUT WCHAR const** textString,
    66                                 OUT UINT32* textLength)
    67 {
    68     if (textPosition >= mTextLength) {
    69         // No text at this position, valid query though.
    70         *textString = nullptr;
    71         *textLength = 0;
    72     } else {
    73         *textString = mText + textPosition;
    74         *textLength = mTextLength - textPosition;
    75     }
    76     return S_OK;
    77 }
    80 IFACEMETHODIMP 
    81 TextAnalysis::GetTextBeforePosition(UINT32 textPosition,
    82                                     OUT WCHAR const** textString,
    83                                     OUT UINT32* textLength)
    84 {
    85     if (textPosition == 0 || textPosition > mTextLength) {
    86         // Either there is no text before here (== 0), or this
    87         // is an invalid position. The query is considered valid thouh.
    88         *textString = nullptr;
    89         *textLength = 0;
    90     } else {
    91         *textString = mText;
    92         *textLength = textPosition;
    93     }
    94     return S_OK;
    95 }
    98 DWRITE_READING_DIRECTION STDMETHODCALLTYPE 
    99 TextAnalysis::GetParagraphReadingDirection()
   100 {
   101     // We support only a single reading direction.
   102     return mReadingDirection;
   103 }
   106 IFACEMETHODIMP 
   107 TextAnalysis::GetLocaleName(UINT32 textPosition,
   108                             OUT UINT32* textLength,
   109                             OUT WCHAR const** localeName)
   110 {
   111     // Single locale name is used, valid until the end of the string.
   112     *localeName = mLocaleName;
   113     *textLength = mTextLength - textPosition;
   115     return S_OK;
   116 }
   119 IFACEMETHODIMP 
   120 TextAnalysis::GetNumberSubstitution(UINT32 textPosition,
   121                                     OUT UINT32* textLength,
   122                                     OUT IDWriteNumberSubstitution** numberSubstitution)
   123 {
   124     // We do not support number substitution.
   125     *numberSubstitution = nullptr;
   126     *textLength = mTextLength - textPosition;
   128     return S_OK;
   129 }
   132 ////////////////////////////////////////////////////////////////////////////////
   133 // IDWriteTextAnalysisSink implementation
   135 IFACEMETHODIMP 
   136 TextAnalysis::SetLineBreakpoints(UINT32 textPosition,
   137                                  UINT32 textLength,
   138                                  DWRITE_LINE_BREAKPOINT const* lineBreakpoints)
   139 {
   140     // We don't use this for now.
   141     return S_OK;
   142 }
   145 IFACEMETHODIMP 
   146 TextAnalysis::SetScriptAnalysis(UINT32 textPosition,
   147                                 UINT32 textLength,
   148                                 DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
   149 {
   150     SetCurrentRun(textPosition);
   151     SplitCurrentRun(textPosition);
   152     while (textLength > 0) {
   153         Run *run = FetchNextRun(&textLength);
   154         run->mScript = *scriptAnalysis;
   155     }
   157     return S_OK;
   158 }
   161 IFACEMETHODIMP 
   162 TextAnalysis::SetBidiLevel(UINT32 textPosition,
   163                            UINT32 textLength,
   164                            UINT8 explicitLevel,
   165                            UINT8 resolvedLevel)
   166 {
   167     // We don't use this for now.
   168     return S_OK;
   169 }
   172 IFACEMETHODIMP 
   173 TextAnalysis::SetNumberSubstitution(UINT32 textPosition,
   174                                     UINT32 textLength,
   175                                     IDWriteNumberSubstitution* numberSubstitution)
   176 {
   177     // We don't use this for now.
   178     return S_OK;
   179 }
   182 ////////////////////////////////////////////////////////////////////////////////
   183 // Run modification.
   185 TextAnalysis::Run *
   186 TextAnalysis::FetchNextRun(IN OUT UINT32* textLength)
   187 {
   188     // Used by the sink setters, this returns a reference to the next run.
   189     // Position and length are adjusted to now point after the current run
   190     // being returned.
   192     Run *origRun = mCurrentRun;
   193     // Split the tail if needed (the length remaining is less than the
   194     // current run's size).
   195     if (*textLength < mCurrentRun->mTextLength) {
   196         SplitCurrentRun(mCurrentRun->mTextStart + *textLength);
   197     } else {
   198         // Just advance the current run.
   199         mCurrentRun = mCurrentRun->nextRun;
   200     }
   201     *textLength -= origRun->mTextLength;
   203     // Return a reference to the run that was just current.
   204     return origRun;
   205 }
   208 void TextAnalysis::SetCurrentRun(UINT32 textPosition)
   209 {
   210     // Move the current run to the given position.
   211     // Since the analyzers generally return results in a forward manner,
   212     // this will usually just return early. If not, find the
   213     // corresponding run for the text position.
   215     if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
   216         return;
   217     }
   219     for (Run *run = &mRunHead; run; run = run->nextRun) {
   220         if (run->ContainsTextPosition(textPosition)) {
   221             mCurrentRun = run;
   222             return;
   223         }
   224     }
   225     NS_NOTREACHED("We should always be able to find the text position in one \
   226         of our runs");
   227 }
   230 void TextAnalysis::SplitCurrentRun(UINT32 splitPosition)
   231 {
   232     if (!mCurrentRun) {
   233         NS_ASSERTION(false, "SplitCurrentRun called without current run.");
   234         // Shouldn't be calling this when no current run is set!
   235         return;
   236     }
   237     // Split the current run.
   238     if (splitPosition <= mCurrentRun->mTextStart) {
   239         // No need to split, already the start of a run
   240         // or before it. Usually the first.
   241         return;
   242     }
   243     Run *newRun = new Run;
   245     *newRun = *mCurrentRun;
   247     // Insert the new run in our linked list.
   248     newRun->nextRun = mCurrentRun->nextRun;
   249     mCurrentRun->nextRun = newRun;
   251     // Adjust runs' text positions and lengths.
   252     UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart;
   253     newRun->mTextStart += splitPoint;
   254     newRun->mTextLength -= splitPoint;
   255     mCurrentRun->mTextLength = splitPoint;
   256     mCurrentRun = newRun;
   257 }

mercurial