gfx/layers/composite/TextRenderer.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/layers/composite/TextRenderer.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,163 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "TextRenderer.h"
    1.10 +#include "FontData.h"
    1.11 +#include "png.h"
    1.12 +#include "mozilla/Base64.h"
    1.13 +#include "mozilla/layers/Compositor.h"
    1.14 +#include "mozilla/layers/TextureHost.h"
    1.15 +#include "mozilla/layers/Effects.h"
    1.16 +
    1.17 +namespace mozilla {
    1.18 +namespace layers {
    1.19 +
    1.20 +using namespace gfx;
    1.21 +using namespace std;
    1.22 +
    1.23 +const Float sBackgroundOpacity = 0.6f;
    1.24 +const SurfaceFormat sTextureFormat = SurfaceFormat::B8G8R8A8;
    1.25 +
    1.26 +static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr)
    1.27 +{
    1.28 +  png_read_update_info(png_ptr, info_ptr);
    1.29 +}
    1.30 +
    1.31 +static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass)
    1.32 +{
    1.33 +  MOZ_ASSERT(sTextureFormat == SurfaceFormat::B8G8R8A8);
    1.34 +
    1.35 +  DataSourceSurface::MappedSurface map = static_cast<TextRenderer*>(png_get_progressive_ptr(png_ptr))->GetSurfaceMap();
    1.36 +
    1.37 +  uint32_t* dst = (uint32_t*)(map.mData + map.mStride * row_num);
    1.38 +
    1.39 +  for (uint32_t x = 0; x < sTextureWidth; x++) {
    1.40 +    // We blend to a transparent white background, this will make text readable
    1.41 +    // even if it's on a dark background. Without hurting our ability to
    1.42 +    // interact with the content behind the text.
    1.43 +    Float alphaValue = Float(0xFF - new_row[x]) / 255.0f;
    1.44 +    Float baseValue = sBackgroundOpacity * (1.0f - alphaValue);
    1.45 +    Color pixelColor(baseValue, baseValue, baseValue, baseValue + alphaValue);
    1.46 +    dst[x] = pixelColor.ToABGR();
    1.47 +  }
    1.48 +}
    1.49 +
    1.50 +TextRenderer::~TextRenderer()
    1.51 +{
    1.52 +  if (mGlyphBitmaps) {
    1.53 +    mGlyphBitmaps->Unmap();
    1.54 +  }
    1.55 +}
    1.56 +
    1.57 +void
    1.58 +TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin,
    1.59 +                         const Matrix4x4& aTransform, uint32_t aTextSize,
    1.60 +                         uint32_t aTargetPixelWidth)
    1.61 +{
    1.62 +  EnsureInitialized();
    1.63 +
    1.64 +  // For now we only have a bitmap font with a 16px cell size, so we just
    1.65 +  // scale it up if the user wants larger text.
    1.66 +  Float scaleFactor = Float(aTextSize) / Float(sCellHeight);
    1.67 +
    1.68 +  aTargetPixelWidth /= scaleFactor;
    1.69 +
    1.70 +  uint32_t numLines = 1;
    1.71 +  uint32_t maxWidth = 0;
    1.72 +  uint32_t lineWidth = 0;
    1.73 +  // Calculate the size of the surface needed to draw all the glyphs.
    1.74 +  for (uint32_t i = 0; i < aText.length(); i++) {
    1.75 +    // Insert a line break if we go past the TargetPixelWidth.
    1.76 +    // XXX - this has the downside of overrunning the intended width, causing
    1.77 +    // things at the edge of a window to be cut off.
    1.78 +    if (aText[i] == '\n' || (aText[i] == ' ' && lineWidth > aTargetPixelWidth)) {
    1.79 +      numLines++;
    1.80 +      lineWidth = 0;
    1.81 +      continue;
    1.82 +    }
    1.83 +
    1.84 +    lineWidth += sGlyphWidths[uint32_t(aText[i])];
    1.85 +    maxWidth = std::max(lineWidth, maxWidth);
    1.86 +  }
    1.87 +
    1.88 +  // Create a surface to draw our glyphs to.
    1.89 +  RefPtr<DataSourceSurface> textSurf =
    1.90 +    Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * sCellHeight), sTextureFormat);
    1.91 +
    1.92 +  DataSourceSurface::MappedSurface map;
    1.93 +  textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map);
    1.94 +
    1.95 +  // Initialize the surface to transparent white.
    1.96 +  memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f),
    1.97 +         numLines * sCellHeight * map.mStride);
    1.98 +
    1.99 +  uint32_t currentXPos = 0;
   1.100 +  uint32_t currentYPos = 0;
   1.101 +
   1.102 +  // Copy our glyphs onto the surface.
   1.103 +  for (uint32_t i = 0; i < aText.length(); i++) {
   1.104 +    if (aText[i] == '\n' || (aText[i] == ' ' && currentXPos > aTargetPixelWidth)) {
   1.105 +      currentYPos += sCellHeight;
   1.106 +      currentXPos = 0;
   1.107 +      continue;
   1.108 +    }
   1.109 +
   1.110 +    uint32_t glyphXOffset = aText[i] % (sTextureWidth / sCellWidth) * sCellWidth * BytesPerPixel(sTextureFormat);
   1.111 +    uint32_t truncatedLine = aText[i] / (sTextureWidth / sCellWidth);
   1.112 +    uint32_t glyphYOffset =  truncatedLine * sCellHeight * mMap.mStride;
   1.113 +
   1.114 +    for (int y = 0; y < 16; y++) {
   1.115 +      memcpy(map.mData + (y + currentYPos) * map.mStride + currentXPos * BytesPerPixel(sTextureFormat),
   1.116 +             mMap.mData + glyphYOffset + y * mMap.mStride + glyphXOffset,
   1.117 +             sGlyphWidths[uint32_t(aText[i])] * BytesPerPixel(sTextureFormat));
   1.118 +    }
   1.119 +
   1.120 +    currentXPos += sGlyphWidths[uint32_t(aText[i])];
   1.121 +  }
   1.122 +
   1.123 +  textSurf->Unmap();
   1.124 +
   1.125 +  RefPtr<DataTextureSource> src = mCompositor->CreateDataTextureSource();
   1.126 +
   1.127 +  if (!src->Update(textSurf)) {
   1.128 +    // Upload failed.
   1.129 +    return;
   1.130 +  }
   1.131 +
   1.132 +  RefPtr<EffectRGB> effect = new EffectRGB(src, true, Filter::LINEAR);
   1.133 +  EffectChain chain;
   1.134 +  chain.mPrimaryEffect = effect;
   1.135 +
   1.136 +  Matrix4x4 transform = aTransform;
   1.137 +  transform.Scale(scaleFactor, scaleFactor, 1.0f);
   1.138 +  mCompositor->DrawQuad(Rect(aOrigin.x, aOrigin.y, maxWidth, numLines * 16),
   1.139 +                        Rect(-10000, -10000, 20000, 20000), chain, 1.0f, transform);
   1.140 +}
   1.141 +
   1.142 +void
   1.143 +TextRenderer::EnsureInitialized()
   1.144 +{
   1.145 +  if (mGlyphBitmaps) {
   1.146 +    return;
   1.147 +  }
   1.148 +
   1.149 +  mGlyphBitmaps = Factory::CreateDataSourceSurface(IntSize(sTextureWidth, sTextureHeight), sTextureFormat);
   1.150 +
   1.151 +  mGlyphBitmaps->Map(DataSourceSurface::MapType::READ_WRITE, &mMap);
   1.152 +
   1.153 +  png_structp png_ptr = NULL;
   1.154 +  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
   1.155 +
   1.156 +  png_set_progressive_read_fn(png_ptr, this, info_callback, row_callback, nullptr);
   1.157 +  png_infop info_ptr = NULL;
   1.158 +  info_ptr = png_create_info_struct(png_ptr);
   1.159 +
   1.160 +  png_process_data(png_ptr, info_ptr, (uint8_t*)sFontPNG, sizeof(sFontPNG));
   1.161 +
   1.162 +  png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
   1.163 +}
   1.164 +
   1.165 +}
   1.166 +}

mercurial