tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsUniscribeBreaker.cpp (4831B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      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/. */
      5 
      6 #include "nsComplexBreaker.h"
      7 
      8 #include <windows.h>
      9 
     10 #include <usp10.h>
     11 
     12 #include "nsUTF8Utils.h"
     13 #include "nsString.h"
     14 #include "nsTArray.h"
     15 
     16 #if defined(MOZ_SANDBOX)
     17 #  include "mozilla/WindowsProcessMitigations.h"
     18 #  include "mozilla/SandboxSettings.h"
     19 #  include "mozilla/sandboxTarget.h"
     20 #  include "nsXULAppAPI.h"
     21 
     22 #  if defined(MOZ_DEBUG)
     23 #    include "mozilla/StaticPrefs_intl.h"
     24 #  endif
     25 #endif
     26 
     27 using namespace mozilla;
     28 
     29 #if defined(MOZ_SANDBOX)
     30 static bool UseBrokeredLineBreaking() {
     31  // If win32k lockdown is enabled we can't use Uniscribe in this process. Also
     32  // if the sandbox is above a certain level we can't load the required DLLs
     33  // without other intervention. Given that it looks like we are likely to have
     34  // win32k lockdown enabled first, using the brokered call for people testing
     35  // this case also makes most sense.
     36  static bool sUseBrokeredLineBreaking =
     37      IsWin32kLockedDown() ||
     38      (XRE_IsContentProcess() && GetEffectiveContentSandboxLevel() >= 20);
     39 
     40  return sUseBrokeredLineBreaking;
     41 }
     42 #endif
     43 
     44 void NS_GetComplexLineBreaks(const char16_t* aText, uint32_t aLength,
     45                             uint8_t* aBreakBefore) {
     46  NS_ASSERTION(aText, "aText shouldn't be null");
     47 
     48 #if defined(MOZ_SANDBOX)
     49  if (UseBrokeredLineBreaking()) {
     50    // We can't use Uniscribe, so use a brokered call. Use of Uniscribe will be
     51    // replaced in bug 1684927.
     52    char16ptr_t text = aText;
     53    if (!SandboxTarget::Instance()->GetComplexLineBreaks(text, aLength,
     54                                                         aBreakBefore)) {
     55      NS_WARNING("Brokered line break failed, breaks might be incorrect.");
     56    }
     57 
     58    return;
     59  }
     60 #endif
     61 
     62  int outItems = 0;
     63  HRESULT result;
     64  AutoTArray<SCRIPT_ITEM, 64> items;
     65  char16ptr_t text = aText;
     66 
     67  memset(aBreakBefore, false, aLength);
     68 
     69  items.AppendElements(64);
     70 
     71  do {
     72    result = ScriptItemize(text, aLength, items.Length(), nullptr, nullptr,
     73                           items.Elements(), &outItems);
     74 
     75    if (result == E_OUTOFMEMORY) {
     76      // XXX(Bug 1631371) Check if this should use a fallible operation as it
     77      // pretended earlier.
     78      items.AppendElements(items.Length());
     79    }
     80  } while (result == E_OUTOFMEMORY);
     81 
     82  for (int iItem = 0; iItem < outItems; ++iItem) {
     83    uint32_t endOffset =
     84        (iItem + 1 == outItems ? aLength : items[iItem + 1].iCharPos);
     85    uint32_t startOffset = items[iItem].iCharPos;
     86    AutoTArray<SCRIPT_LOGATTR, 64> sla;
     87 
     88    // XXX(Bug 1631371) Check if this should use a fallible operation as it
     89    // pretended earlier.
     90    sla.AppendElements(endOffset - startOffset);
     91 
     92    if (ScriptBreak(text + startOffset, endOffset - startOffset,
     93                    &items[iItem].a, sla.Elements()) < 0)
     94      return;
     95 
     96    // We don't want to set a potential break position at the start of text;
     97    // that's the responsibility of a higher level.
     98    for (uint32_t j = startOffset ? 0 : 1; j + startOffset < endOffset; ++j) {
     99      aBreakBefore[j + startOffset] = sla[j].fSoftBreak;
    100    }
    101  }
    102 
    103 #if defined(MOZ_DEBUG) && defined(MOZ_SANDBOX)
    104  // When tests are enabled and pref is set, we compare the line breaks returned
    105  // from the Uniscribe breaker in the content process, with the ones returned
    106  // from the brokered call to the parent. If they differ we crash so we can
    107  // test using a crashtest.
    108  if (!StaticPrefs::intl_compare_against_brokered_complex_line_breaks() ||
    109      !XRE_IsContentProcess()) {
    110    return;
    111  }
    112 
    113  nsTArray<uint8_t> brokeredBreaks(aLength);
    114  brokeredBreaks.AppendElements(aLength);
    115  if (!SandboxTarget::Instance()->GetComplexLineBreaks(
    116          text, aLength, brokeredBreaks.Elements())) {
    117    MOZ_CRASH("Brokered GetComplexLineBreaks failed.");
    118  }
    119 
    120  bool mismatch = false;
    121  for (uint32_t i = 0; i < aLength; ++i) {
    122    if (aBreakBefore[i] != brokeredBreaks[i]) {
    123      mismatch = true;
    124      break;
    125    }
    126  }
    127 
    128  if (mismatch) {
    129    nsCString line("uniscribe: ");
    130    // The logging here doesn't handle surrogates, but we only have tests using
    131    // Thai currently, which is BMP-only.
    132    for (uint32_t i = 0; i < aLength; ++i) {
    133      if (aBreakBefore[i]) line.Append('#');
    134      line.Append(NS_ConvertUTF16toUTF8(aText + i, 1).get());
    135    }
    136    printf_stderr("%s\n", line.get());
    137    line.Assign("brokered : ");
    138    for (uint32_t i = 0; i < aLength; ++i) {
    139      if (brokeredBreaks[i]) line.Append('#');
    140      line.Append(NS_ConvertUTF16toUTF8(aText + i, 1).get());
    141    }
    142    printf_stderr("%s\n", line.get());
    143    MOZ_CRASH("Brokered breaks did not match.");
    144  }
    145 #endif
    146 }