mfbt/Char16.h
author Alexis Beingessner <a.beingessner@gmail.com>
Mon, 19 Jun 2017 10:58:28 -0400
changeset 424982 564959d26e8db243ded3d57380842620e60e89e7
parent 412540 f6f2a58bedb3f533453c3e2823b60671fe9d5de1
child 449882 48cddb40b16b99fac6342b6503b0b6e67be4dbc2
permissions -rw-r--r--
Bug 1357545 - handle text-shadows/decorations with webrender (layers-free) r=jrmuizel This replaces our DrawTargetCapture hack with a similar but more powerful TextDrawTarget hack. The old design had several limitations: * It couldn't handle shadows * It couldn't handle selections * It couldn't handle font/color changes in a single text-run * It couldn't handle decorations (underline, overline, line-through) Mostly this was a consequence of the fact that it only modified the start and end of the rendering algorithm, and therefore couldn't distinguish draw calls for different parts of the text. This new design is based on a similar principle as DrawTargetCapture, but also passes down the TextDrawTarget in the drawing arguments, so that the drawing algorithm can notify us of changes in phase (e.g. "now we're doing underlines"). This also lets us directly pass data to TextDrawTarget when possible (as is done for shadows and selections). In doing this, I also improved the logic copied from ContainsOnlyColoredGlyphs to handle changes in font/color mid-text-run (which can happen because of font fallback). The end result is: * We handle all shadows natively * We handle all selections natively * We handle all decorations natively * We handle font/color changes in a single text-run * Although we still hackily intercept draw calls * But we don't need to buffer commands, reducing total memcopies In addition, this change integrates webrender's PushTextShadow and PushLine APIs, which were designed for this use case. This is only done in the layerless path; WebrenderTextLayer continues to be semantically limited, as we aren't actively maintaining non-layers-free webrender anymore. This also doesn't modify TextLayers, to minimize churn. In theory they can be augmented to support the richer semantics that TextDrawTarget has, but there's little motivation since the API is largely unused with this change. MozReview-Commit-ID: 4IjTsSW335h

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */

/* Implements a UTF-16 character type. */

#ifndef mozilla_Char16_h
#define mozilla_Char16_h

#ifdef __cplusplus

/*
 * C++11 introduces a char16_t type and support for UTF-16 string and character
 * literals. C++11's char16_t is a distinct builtin type. Technically, char16_t
 * is a 16-bit code unit of a Unicode code point, not a "character".
 */

#ifdef WIN32
# define MOZ_USE_CHAR16_WRAPPER
# include <cstdint>
# include "mozilla/Attributes.h"
  /**
   * Win32 API extensively uses wchar_t, which is represented by a separated
   * builtin type than char16_t per spec. It's not the case for MSVC prior to
   * MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and
   * char16_t on Windows builds. This class is supposed to make it easier. It
   * stores char16_t const pointer, but provides implicit casts for wchar_t as
   * well. On other platforms, we simply use
   * |typedef const char16_t* char16ptr_t|. Here, we want to make the class as
   * similar to this typedef, including providing some casts that are allowed
   * by the typedef.
   */
class char16ptr_t
{
private:
  const char16_t* mPtr;
  static_assert(sizeof(char16_t) == sizeof(wchar_t),
                "char16_t and wchar_t sizes differ");

public:
  MOZ_IMPLICIT char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {}
  MOZ_IMPLICIT char16ptr_t(const wchar_t* aPtr) :
    mPtr(reinterpret_cast<const char16_t*>(aPtr))
  {}

  /* Without this, nullptr assignment would be ambiguous. */
  constexpr MOZ_IMPLICIT char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {}

  operator const char16_t*() const
  {
    return mPtr;
  }
  operator const wchar_t*() const
  {
    return reinterpret_cast<const wchar_t*>(mPtr);
  }

  operator wchar_t*()
  {
    return const_cast<wchar_t*>(reinterpret_cast<const wchar_t*>(mPtr));
  }

  operator const void*() const
  {
    return mPtr;
  }
  MOZ_IMPLICIT operator bool() const
  {
    return mPtr != nullptr;
  }

  /* Explicit cast operators to allow things like (char16_t*)str. */
  explicit operator char16_t*() const
  {
    return const_cast<char16_t*>(mPtr);
  }
  explicit operator wchar_t*() const
  {
    return const_cast<wchar_t*>(static_cast<const wchar_t*>(*this));
  }
  explicit operator int() const
  {
    return reinterpret_cast<intptr_t>(mPtr);
  }
  explicit operator unsigned int() const
  {
    return reinterpret_cast<uintptr_t>(mPtr);
  }
  explicit operator long() const
  {
    return reinterpret_cast<intptr_t>(mPtr);
  }
  explicit operator unsigned long() const
  {
    return reinterpret_cast<uintptr_t>(mPtr);
  }
  explicit operator long long() const
  {
    return reinterpret_cast<intptr_t>(mPtr);
  }
  explicit operator unsigned long long() const
  {
    return reinterpret_cast<uintptr_t>(mPtr);
  }

  /**
   * Some Windows API calls accept BYTE* but require that data actually be
   * WCHAR*.  Supporting this requires explicit operators to support the
   * requisite explicit casts.
   */
  explicit operator const char*() const
  {
    return reinterpret_cast<const char*>(mPtr);
  }
  explicit operator const unsigned char*() const
  {
    return reinterpret_cast<const unsigned char*>(mPtr);
  }
  explicit operator unsigned char*() const
  {
    return
      const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(mPtr));
  }
  explicit operator void*() const
  {
    return const_cast<char16_t*>(mPtr);
  }

  /* Some operators used on pointers. */
  char16_t operator[](size_t aIndex) const
  {
    return mPtr[aIndex];
  }
  bool operator==(const char16ptr_t& aOther) const
  {
    return mPtr == aOther.mPtr;
  }
  bool operator==(decltype(nullptr)) const
  {
    return mPtr == nullptr;
  }
  bool operator!=(const char16ptr_t& aOther) const
  {
    return mPtr != aOther.mPtr;
  }
  bool operator!=(decltype(nullptr)) const
  {
    return mPtr != nullptr;
  }
  char16ptr_t operator+(int aValue) const
  {
    return char16ptr_t(mPtr + aValue);
  }
  char16ptr_t operator+(unsigned int aValue) const
  {
    return char16ptr_t(mPtr + aValue);
  }
  char16ptr_t operator+(long aValue) const
  {
    return char16ptr_t(mPtr + aValue);
  }
  char16ptr_t operator+(unsigned long aValue) const
  {
    return char16ptr_t(mPtr + aValue);
  }
  char16ptr_t operator+(long long aValue) const
  {
    return char16ptr_t(mPtr + aValue);
  }
  char16ptr_t operator+(unsigned long long aValue) const
  {
    return char16ptr_t(mPtr + aValue);
  }
  ptrdiff_t operator-(const char16ptr_t& aOther) const
  {
    return mPtr - aOther.mPtr;
  }
};

inline decltype((char*)0-(char*)0)
operator-(const char16_t* aX, const char16ptr_t aY)
{
  return aX - static_cast<const char16_t*>(aY);
}

#else

typedef const char16_t* char16ptr_t;

#endif

static_assert(sizeof(char16_t) == 2, "Is char16_t type 16 bits?");
static_assert(char16_t(-1) > char16_t(0), "Is char16_t type unsigned?");
static_assert(sizeof(u'A') == 2, "Is unicode char literal 16 bits?");
static_assert(sizeof(u""[0]) == 2, "Is unicode string char 16 bits?");

#endif

#endif /* mozilla_Char16_h */