|
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/. */ |
|
5 |
|
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" |
|
13 |
|
14 namespace mozilla { |
|
15 namespace layers { |
|
16 |
|
17 using namespace gfx; |
|
18 using namespace std; |
|
19 |
|
20 const Float sBackgroundOpacity = 0.6f; |
|
21 const SurfaceFormat sTextureFormat = SurfaceFormat::B8G8R8A8; |
|
22 |
|
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 } |
|
27 |
|
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); |
|
31 |
|
32 DataSourceSurface::MappedSurface map = static_cast<TextRenderer*>(png_get_progressive_ptr(png_ptr))->GetSurfaceMap(); |
|
33 |
|
34 uint32_t* dst = (uint32_t*)(map.mData + map.mStride * row_num); |
|
35 |
|
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 } |
|
46 |
|
47 TextRenderer::~TextRenderer() |
|
48 { |
|
49 if (mGlyphBitmaps) { |
|
50 mGlyphBitmaps->Unmap(); |
|
51 } |
|
52 } |
|
53 |
|
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(); |
|
60 |
|
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); |
|
64 |
|
65 aTargetPixelWidth /= scaleFactor; |
|
66 |
|
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 } |
|
80 |
|
81 lineWidth += sGlyphWidths[uint32_t(aText[i])]; |
|
82 maxWidth = std::max(lineWidth, maxWidth); |
|
83 } |
|
84 |
|
85 // Create a surface to draw our glyphs to. |
|
86 RefPtr<DataSourceSurface> textSurf = |
|
87 Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * sCellHeight), sTextureFormat); |
|
88 |
|
89 DataSourceSurface::MappedSurface map; |
|
90 textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map); |
|
91 |
|
92 // Initialize the surface to transparent white. |
|
93 memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f), |
|
94 numLines * sCellHeight * map.mStride); |
|
95 |
|
96 uint32_t currentXPos = 0; |
|
97 uint32_t currentYPos = 0; |
|
98 |
|
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 } |
|
106 |
|
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; |
|
110 |
|
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 } |
|
116 |
|
117 currentXPos += sGlyphWidths[uint32_t(aText[i])]; |
|
118 } |
|
119 |
|
120 textSurf->Unmap(); |
|
121 |
|
122 RefPtr<DataTextureSource> src = mCompositor->CreateDataTextureSource(); |
|
123 |
|
124 if (!src->Update(textSurf)) { |
|
125 // Upload failed. |
|
126 return; |
|
127 } |
|
128 |
|
129 RefPtr<EffectRGB> effect = new EffectRGB(src, true, Filter::LINEAR); |
|
130 EffectChain chain; |
|
131 chain.mPrimaryEffect = effect; |
|
132 |
|
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 } |
|
138 |
|
139 void |
|
140 TextRenderer::EnsureInitialized() |
|
141 { |
|
142 if (mGlyphBitmaps) { |
|
143 return; |
|
144 } |
|
145 |
|
146 mGlyphBitmaps = Factory::CreateDataSourceSurface(IntSize(sTextureWidth, sTextureHeight), sTextureFormat); |
|
147 |
|
148 mGlyphBitmaps->Map(DataSourceSurface::MapType::READ_WRITE, &mMap); |
|
149 |
|
150 png_structp png_ptr = NULL; |
|
151 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
|
152 |
|
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); |
|
156 |
|
157 png_process_data(png_ptr, info_ptr, (uint8_t*)sFontPNG, sizeof(sFontPNG)); |
|
158 |
|
159 png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); |
|
160 } |
|
161 |
|
162 } |
|
163 } |