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 +}