Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 20; 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/. */
6 #include "TextRenderer.h"
7 #include "FontData.h"
8 #include "png.h"
9 #include "mozilla/Base64.h"
10 #include "mozilla/layers/Compositor.h"
11 #include "mozilla/layers/TextureHost.h"
12 #include "mozilla/layers/Effects.h"
14 namespace mozilla {
15 namespace layers {
17 using namespace gfx;
18 using namespace std;
20 const Float sBackgroundOpacity = 0.6f;
21 const SurfaceFormat sTextureFormat = SurfaceFormat::B8G8R8A8;
23 static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr)
24 {
25 png_read_update_info(png_ptr, info_ptr);
26 }
28 static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass)
29 {
30 MOZ_ASSERT(sTextureFormat == SurfaceFormat::B8G8R8A8);
32 DataSourceSurface::MappedSurface map = static_cast<TextRenderer*>(png_get_progressive_ptr(png_ptr))->GetSurfaceMap();
34 uint32_t* dst = (uint32_t*)(map.mData + map.mStride * row_num);
36 for (uint32_t x = 0; x < sTextureWidth; x++) {
37 // We blend to a transparent white background, this will make text readable
38 // even if it's on a dark background. Without hurting our ability to
39 // interact with the content behind the text.
40 Float alphaValue = Float(0xFF - new_row[x]) / 255.0f;
41 Float baseValue = sBackgroundOpacity * (1.0f - alphaValue);
42 Color pixelColor(baseValue, baseValue, baseValue, baseValue + alphaValue);
43 dst[x] = pixelColor.ToABGR();
44 }
45 }
47 TextRenderer::~TextRenderer()
48 {
49 if (mGlyphBitmaps) {
50 mGlyphBitmaps->Unmap();
51 }
52 }
54 void
55 TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin,
56 const Matrix4x4& aTransform, uint32_t aTextSize,
57 uint32_t aTargetPixelWidth)
58 {
59 EnsureInitialized();
61 // For now we only have a bitmap font with a 16px cell size, so we just
62 // scale it up if the user wants larger text.
63 Float scaleFactor = Float(aTextSize) / Float(sCellHeight);
65 aTargetPixelWidth /= scaleFactor;
67 uint32_t numLines = 1;
68 uint32_t maxWidth = 0;
69 uint32_t lineWidth = 0;
70 // Calculate the size of the surface needed to draw all the glyphs.
71 for (uint32_t i = 0; i < aText.length(); i++) {
72 // Insert a line break if we go past the TargetPixelWidth.
73 // XXX - this has the downside of overrunning the intended width, causing
74 // things at the edge of a window to be cut off.
75 if (aText[i] == '\n' || (aText[i] == ' ' && lineWidth > aTargetPixelWidth)) {
76 numLines++;
77 lineWidth = 0;
78 continue;
79 }
81 lineWidth += sGlyphWidths[uint32_t(aText[i])];
82 maxWidth = std::max(lineWidth, maxWidth);
83 }
85 // Create a surface to draw our glyphs to.
86 RefPtr<DataSourceSurface> textSurf =
87 Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * sCellHeight), sTextureFormat);
89 DataSourceSurface::MappedSurface map;
90 textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map);
92 // Initialize the surface to transparent white.
93 memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f),
94 numLines * sCellHeight * map.mStride);
96 uint32_t currentXPos = 0;
97 uint32_t currentYPos = 0;
99 // Copy our glyphs onto the surface.
100 for (uint32_t i = 0; i < aText.length(); i++) {
101 if (aText[i] == '\n' || (aText[i] == ' ' && currentXPos > aTargetPixelWidth)) {
102 currentYPos += sCellHeight;
103 currentXPos = 0;
104 continue;
105 }
107 uint32_t glyphXOffset = aText[i] % (sTextureWidth / sCellWidth) * sCellWidth * BytesPerPixel(sTextureFormat);
108 uint32_t truncatedLine = aText[i] / (sTextureWidth / sCellWidth);
109 uint32_t glyphYOffset = truncatedLine * sCellHeight * mMap.mStride;
111 for (int y = 0; y < 16; y++) {
112 memcpy(map.mData + (y + currentYPos) * map.mStride + currentXPos * BytesPerPixel(sTextureFormat),
113 mMap.mData + glyphYOffset + y * mMap.mStride + glyphXOffset,
114 sGlyphWidths[uint32_t(aText[i])] * BytesPerPixel(sTextureFormat));
115 }
117 currentXPos += sGlyphWidths[uint32_t(aText[i])];
118 }
120 textSurf->Unmap();
122 RefPtr<DataTextureSource> src = mCompositor->CreateDataTextureSource();
124 if (!src->Update(textSurf)) {
125 // Upload failed.
126 return;
127 }
129 RefPtr<EffectRGB> effect = new EffectRGB(src, true, Filter::LINEAR);
130 EffectChain chain;
131 chain.mPrimaryEffect = effect;
133 Matrix4x4 transform = aTransform;
134 transform.Scale(scaleFactor, scaleFactor, 1.0f);
135 mCompositor->DrawQuad(Rect(aOrigin.x, aOrigin.y, maxWidth, numLines * 16),
136 Rect(-10000, -10000, 20000, 20000), chain, 1.0f, transform);
137 }
139 void
140 TextRenderer::EnsureInitialized()
141 {
142 if (mGlyphBitmaps) {
143 return;
144 }
146 mGlyphBitmaps = Factory::CreateDataSourceSurface(IntSize(sTextureWidth, sTextureHeight), sTextureFormat);
148 mGlyphBitmaps->Map(DataSourceSurface::MapType::READ_WRITE, &mMap);
150 png_structp png_ptr = NULL;
151 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
153 png_set_progressive_read_fn(png_ptr, this, info_callback, row_callback, nullptr);
154 png_infop info_ptr = NULL;
155 info_ptr = png_create_info_struct(png_ptr);
157 png_process_data(png_ptr, info_ptr, (uint8_t*)sFontPNG, sizeof(sFontPNG));
159 png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
160 }
162 }
163 }