Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/composite/TextRenderer.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "TextRenderer.h"
8
#include "FontData.h"
9
#include "ConsolasFontData.h"
10
#include "png.h"
11
#include "mozilla/Base64.h"
12
#include "mozilla/layers/Compositor.h"
13
#include "mozilla/layers/TextureHost.h"
14
#include "mozilla/layers/Effects.h"
15
16
namespace mozilla {
17
namespace layers {
18
19
using namespace gfx;
20
using namespace std;
21
22
const Float sBackgroundOpacity = 0.8f;
23
const SurfaceFormat sTextureFormat = SurfaceFormat::B8G8R8A8;
24
25
static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr)
26
0
{
27
0
  png_read_update_info(png_ptr, info_ptr);
28
0
}
29
30
static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass)
31
0
{
32
0
  MOZ_ASSERT(sTextureFormat == SurfaceFormat::B8G8R8A8);
33
0
34
0
  TextRenderer::FontCache* cache =
35
0
    static_cast<TextRenderer::FontCache*>(png_get_progressive_ptr(png_ptr));
36
0
37
0
  uint32_t* dst = (uint32_t*)(cache->mMap.mData + cache->mMap.mStride * row_num);
38
0
39
0
  for (uint32_t x = 0; x < cache->mInfo->mTextureWidth; x++) {
40
0
    // We blend to a transparent white background, this will make text readable
41
0
    // even if it's on a dark background. Without hurting our ability to
42
0
    // interact with the content behind the text.
43
0
    Float alphaValue = Float(0xFF - new_row[x]) / 255.0f;
44
0
    Float baseValue = sBackgroundOpacity * (1.0f - alphaValue);
45
0
    Color pixelColor(baseValue, baseValue, baseValue, baseValue + alphaValue);
46
0
    dst[x] = pixelColor.ToABGR();
47
0
  }
48
0
}
49
50
TextRenderer::~TextRenderer()
51
0
{
52
0
}
53
54
TextRenderer::FontCache::~FontCache()
55
0
{
56
0
  mGlyphBitmaps->Unmap();
57
0
}
58
59
void
60
TextRenderer::RenderText(Compositor* aCompositor,
61
                         const string& aText,
62
                         const IntPoint& aOrigin,
63
                         const Matrix4x4& aTransform, uint32_t aTextSize,
64
                         uint32_t aTargetPixelWidth,
65
                         FontType aFontType)
66
0
{
67
0
  const FontBitmapInfo* info = GetFontInfo(aFontType);
68
0
69
0
  // For now we only have a bitmap font with a 24px cell size, so we just
70
0
  // scale it up if the user wants larger text.
71
0
  Float scaleFactor = Float(aTextSize) / Float(info->mCellHeight);
72
0
  aTargetPixelWidth /= scaleFactor;
73
0
74
0
  RefPtr<TextureSource> src = RenderText(
75
0
    aCompositor,
76
0
    aText,
77
0
    aTextSize,
78
0
    aTargetPixelWidth,
79
0
    aFontType);
80
0
  if (!src) {
81
0
    return;
82
0
  }
83
0
84
0
  RefPtr<EffectRGB> effect = new EffectRGB(src, true, SamplingFilter::LINEAR);
85
0
  EffectChain chain;
86
0
  chain.mPrimaryEffect = effect;
87
0
88
0
  Matrix4x4 transform = aTransform;
89
0
  transform.PreScale(scaleFactor, scaleFactor, 1.0f);
90
0
91
0
  IntRect drawRect(aOrigin, src->GetSize());
92
0
  IntRect clip(-10000, -10000, 20000, 20000);
93
0
  aCompositor->DrawQuad(Rect(drawRect), clip, chain, 1.0f, transform);
94
0
}
95
96
RefPtr<TextureSource>
97
TextRenderer::RenderText(TextureSourceProvider* aProvider,
98
                         const string& aText,
99
                         uint32_t aTextSize,
100
                         uint32_t aTargetPixelWidth,
101
                         FontType aFontType)
102
0
{
103
0
  if (!EnsureInitialized(aFontType)) {
104
0
    return nullptr;
105
0
  }
106
0
107
0
  FontCache* cache = mFonts[aFontType].get();
108
0
  const FontBitmapInfo* info = cache->mInfo;
109
0
110
0
  uint32_t numLines = 1;
111
0
  uint32_t maxWidth = 0;
112
0
  uint32_t lineWidth = 0;
113
0
  // Calculate the size of the surface needed to draw all the glyphs.
114
0
  for (uint32_t i = 0; i < aText.length(); i++) {
115
0
    // Insert a line break if we go past the TargetPixelWidth.
116
0
    // XXX - this has the downside of overrunning the intended width, causing
117
0
    // things at the edge of a window to be cut off.
118
0
    if (aText[i] == '\n' || (aText[i] == ' ' && lineWidth > aTargetPixelWidth)) {
119
0
      numLines++;
120
0
      lineWidth = 0;
121
0
      continue;
122
0
    }
123
0
124
0
    lineWidth += info->GetGlyphWidth(aText[i]);
125
0
    maxWidth = std::max(lineWidth, maxWidth);
126
0
  }
127
0
128
0
  // Create a surface to draw our glyphs to.
129
0
  RefPtr<DataSourceSurface> textSurf =
130
0
    Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * info->mCellHeight), sTextureFormat);
131
0
  if (NS_WARN_IF(!textSurf)) {
132
0
    return nullptr;
133
0
  }
134
0
135
0
  DataSourceSurface::MappedSurface map;
136
0
  if (NS_WARN_IF(!textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map))) {
137
0
    return nullptr;
138
0
  }
139
0
140
0
  // Initialize the surface to transparent white.
141
0
  memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f),
142
0
         numLines * info->mCellHeight * map.mStride);
143
0
144
0
  uint32_t currentXPos = 0;
145
0
  uint32_t currentYPos = 0;
146
0
147
0
  const unsigned int kGlyphsPerLine = info->mTextureWidth / info->mCellWidth;
148
0
149
0
  // Copy our glyphs onto the surface.
150
0
  for (uint32_t i = 0; i < aText.length(); i++) {
151
0
    if (aText[i] == '\n' || (aText[i] == ' ' && currentXPos > aTargetPixelWidth)) {
152
0
      currentYPos += info->mCellHeight;
153
0
      currentXPos = 0;
154
0
      continue;
155
0
    }
156
0
157
0
    uint32_t index = aText[i] - info->mFirstChar;
158
0
    uint32_t glyphXOffset = (index % kGlyphsPerLine) * info->mCellWidth * BytesPerPixel(sTextureFormat);
159
0
    uint32_t truncatedLine = index / kGlyphsPerLine;
160
0
    uint32_t glyphYOffset =  truncatedLine * info->mCellHeight * cache->mMap.mStride;
161
0
162
0
    uint32_t glyphWidth = info->GetGlyphWidth(aText[i]);
163
0
164
0
    for (uint32_t y = 0; y < info->mCellHeight; y++) {
165
0
      memcpy(map.mData + (y + currentYPos) * map.mStride + currentXPos * BytesPerPixel(sTextureFormat),
166
0
             cache->mMap.mData + glyphYOffset + y * cache->mMap.mStride + glyphXOffset,
167
0
             glyphWidth * BytesPerPixel(sTextureFormat));
168
0
    }
169
0
170
0
    currentXPos += glyphWidth;
171
0
  }
172
0
173
0
  textSurf->Unmap();
174
0
175
0
  RefPtr<DataTextureSource> src = aProvider->CreateDataTextureSource();
176
0
177
0
  if (!src->Update(textSurf)) {
178
0
    // Upload failed.
179
0
    return nullptr;
180
0
  }
181
0
182
0
  return src;
183
0
}
184
185
/* static */ const FontBitmapInfo*
186
TextRenderer::GetFontInfo(FontType aType)
187
0
{
188
0
  switch (aType) {
189
0
  case FontType::Default:
190
0
    return &sDefaultCompositorFont;
191
0
  case FontType::FixedWidth:
192
0
    return &sFixedWidthCompositorFont;
193
0
  default:
194
0
    MOZ_ASSERT_UNREACHABLE("unknown font type");
195
0
    return nullptr;
196
0
  }
197
0
}
198
199
bool
200
TextRenderer::EnsureInitialized(FontType aType)
201
0
{
202
0
  if (mFonts[aType]) {
203
0
    return true;
204
0
  }
205
0
206
0
  const FontBitmapInfo* info = GetFontInfo(aType);
207
0
208
0
  IntSize size(info->mTextureWidth, info->mTextureHeight);
209
0
  RefPtr<DataSourceSurface> surface = Factory::CreateDataSourceSurface(size, sTextureFormat);
210
0
  if (NS_WARN_IF(!surface)) {
211
0
    return false;
212
0
  }
213
0
214
0
  DataSourceSurface::MappedSurface map;
215
0
  if (NS_WARN_IF(!surface->Map(DataSourceSurface::MapType::READ_WRITE, &map))) {
216
0
    return false;
217
0
  }
218
0
219
0
  UniquePtr<FontCache> cache = MakeUnique<FontCache>();
220
0
  cache->mGlyphBitmaps = surface;
221
0
  cache->mMap = map;
222
0
  cache->mInfo = info;
223
0
224
0
  png_structp png_ptr = NULL;
225
0
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
226
0
227
0
  png_set_progressive_read_fn(png_ptr, cache.get(), info_callback, row_callback, nullptr);
228
0
  png_infop info_ptr = NULL;
229
0
  info_ptr = png_create_info_struct(png_ptr);
230
0
231
0
  png_process_data(png_ptr, info_ptr, (uint8_t*)info->mPNG, info->mPNGLength);
232
0
233
0
  png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
234
0
235
0
  mFonts[aType] = std::move(cache);
236
0
  return true;
237
0
}
238
239
} // namespace layers
240
} // namespace mozilla