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.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "gfxFontMissingGlyphs.h" |
michael@0 | 7 | #include "nsDeviceContext.h" |
michael@0 | 8 | #include "gfxContext.h" |
michael@0 | 9 | #include "gfxColor.h" |
michael@0 | 10 | |
michael@0 | 11 | #define CHAR_BITS(b00, b01, b02, b10, b11, b12, b20, b21, b22, b30, b31, b32, b40, b41, b42) \ |
michael@0 | 12 | ((b00 << 0) | (b01 << 1) | (b02 << 2) | (b10 << 3) | (b11 << 4) | (b12 << 5) | \ |
michael@0 | 13 | (b20 << 6) | (b21 << 7) | (b22 << 8) | (b30 << 9) | (b31 << 10) | (b32 << 11) | \ |
michael@0 | 14 | (b40 << 12) | (b41 << 13) | (b42 << 14)) |
michael@0 | 15 | |
michael@0 | 16 | static const uint16_t glyphMicroFont[16] = { |
michael@0 | 17 | CHAR_BITS(0, 1, 0, |
michael@0 | 18 | 1, 0, 1, |
michael@0 | 19 | 1, 0, 1, |
michael@0 | 20 | 1, 0, 1, |
michael@0 | 21 | 0, 1, 0), |
michael@0 | 22 | CHAR_BITS(0, 1, 0, |
michael@0 | 23 | 0, 1, 0, |
michael@0 | 24 | 0, 1, 0, |
michael@0 | 25 | 0, 1, 0, |
michael@0 | 26 | 0, 1, 0), |
michael@0 | 27 | CHAR_BITS(1, 1, 1, |
michael@0 | 28 | 0, 0, 1, |
michael@0 | 29 | 1, 1, 1, |
michael@0 | 30 | 1, 0, 0, |
michael@0 | 31 | 1, 1, 1), |
michael@0 | 32 | CHAR_BITS(1, 1, 1, |
michael@0 | 33 | 0, 0, 1, |
michael@0 | 34 | 1, 1, 1, |
michael@0 | 35 | 0, 0, 1, |
michael@0 | 36 | 1, 1, 1), |
michael@0 | 37 | CHAR_BITS(1, 0, 1, |
michael@0 | 38 | 1, 0, 1, |
michael@0 | 39 | 1, 1, 1, |
michael@0 | 40 | 0, 0, 1, |
michael@0 | 41 | 0, 0, 1), |
michael@0 | 42 | CHAR_BITS(1, 1, 1, |
michael@0 | 43 | 1, 0, 0, |
michael@0 | 44 | 1, 1, 1, |
michael@0 | 45 | 0, 0, 1, |
michael@0 | 46 | 1, 1, 1), |
michael@0 | 47 | CHAR_BITS(1, 1, 1, |
michael@0 | 48 | 1, 0, 0, |
michael@0 | 49 | 1, 1, 1, |
michael@0 | 50 | 1, 0, 1, |
michael@0 | 51 | 1, 1, 1), |
michael@0 | 52 | CHAR_BITS(1, 1, 1, |
michael@0 | 53 | 0, 0, 1, |
michael@0 | 54 | 0, 0, 1, |
michael@0 | 55 | 0, 0, 1, |
michael@0 | 56 | 0, 0, 1), |
michael@0 | 57 | CHAR_BITS(0, 1, 0, |
michael@0 | 58 | 1, 0, 1, |
michael@0 | 59 | 0, 1, 0, |
michael@0 | 60 | 1, 0, 1, |
michael@0 | 61 | 0, 1, 0), |
michael@0 | 62 | CHAR_BITS(1, 1, 1, |
michael@0 | 63 | 1, 0, 1, |
michael@0 | 64 | 1, 1, 1, |
michael@0 | 65 | 0, 0, 1, |
michael@0 | 66 | 0, 0, 1), |
michael@0 | 67 | CHAR_BITS(1, 1, 1, |
michael@0 | 68 | 1, 0, 1, |
michael@0 | 69 | 1, 1, 1, |
michael@0 | 70 | 1, 0, 1, |
michael@0 | 71 | 1, 0, 1), |
michael@0 | 72 | CHAR_BITS(1, 1, 0, |
michael@0 | 73 | 1, 0, 1, |
michael@0 | 74 | 1, 1, 0, |
michael@0 | 75 | 1, 0, 1, |
michael@0 | 76 | 1, 1, 0), |
michael@0 | 77 | CHAR_BITS(0, 1, 1, |
michael@0 | 78 | 1, 0, 0, |
michael@0 | 79 | 1, 0, 0, |
michael@0 | 80 | 1, 0, 0, |
michael@0 | 81 | 0, 1, 1), |
michael@0 | 82 | CHAR_BITS(1, 1, 0, |
michael@0 | 83 | 1, 0, 1, |
michael@0 | 84 | 1, 0, 1, |
michael@0 | 85 | 1, 0, 1, |
michael@0 | 86 | 1, 1, 0), |
michael@0 | 87 | CHAR_BITS(1, 1, 1, |
michael@0 | 88 | 1, 0, 0, |
michael@0 | 89 | 1, 1, 1, |
michael@0 | 90 | 1, 0, 0, |
michael@0 | 91 | 1, 1, 1), |
michael@0 | 92 | CHAR_BITS(1, 1, 1, |
michael@0 | 93 | 1, 0, 0, |
michael@0 | 94 | 1, 1, 1, |
michael@0 | 95 | 1, 0, 0, |
michael@0 | 96 | 1, 0, 0) |
michael@0 | 97 | }; |
michael@0 | 98 | |
michael@0 | 99 | /* Parameters that control the rendering of hexboxes. They look like this: |
michael@0 | 100 | |
michael@0 | 101 | BMP codepoints non-BMP codepoints |
michael@0 | 102 | (U+0000 - U+FFFF) (U+10000 - U+10FFFF) |
michael@0 | 103 | |
michael@0 | 104 | +---------+ +-------------+ |
michael@0 | 105 | | | | | |
michael@0 | 106 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 107 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 108 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 109 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 110 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 111 | | | | | |
michael@0 | 112 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 113 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 114 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 115 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 116 | | HHH HHH | | HHH HHH HHH | |
michael@0 | 117 | | | | | |
michael@0 | 118 | +---------+ +-------------+ |
michael@0 | 119 | */ |
michael@0 | 120 | |
michael@0 | 121 | /** Width of a minifont glyph (see above) */ |
michael@0 | 122 | static const int MINIFONT_WIDTH = 3; |
michael@0 | 123 | /** Height of a minifont glyph (see above) */ |
michael@0 | 124 | static const int MINIFONT_HEIGHT = 5; |
michael@0 | 125 | /** |
michael@0 | 126 | * Gap between minifont glyphs (both horizontal and vertical) and also |
michael@0 | 127 | * the minimum desired gap between the box border and the glyphs |
michael@0 | 128 | */ |
michael@0 | 129 | static const int HEX_CHAR_GAP = 1; |
michael@0 | 130 | /** |
michael@0 | 131 | * The amount of space between the vertical edge of the glyphbox and the |
michael@0 | 132 | * box border. We make this nonzero so that when multiple missing glyphs |
michael@0 | 133 | * occur consecutively there's a gap between their rendered boxes. |
michael@0 | 134 | */ |
michael@0 | 135 | static const int BOX_HORIZONTAL_INSET = 1; |
michael@0 | 136 | /** The width of the border */ |
michael@0 | 137 | static const int BOX_BORDER_WIDTH = 1; |
michael@0 | 138 | /** |
michael@0 | 139 | * The scaling factor for the border opacity; this is multiplied by the current |
michael@0 | 140 | * opacity being used to draw the text. |
michael@0 | 141 | */ |
michael@0 | 142 | static const gfxFloat BOX_BORDER_OPACITY = 0.5; |
michael@0 | 143 | /** |
michael@0 | 144 | * Draw a single hex character using the current color. A nice way to do this |
michael@0 | 145 | * would be to fill in an A8 image surface and then use it as a mask |
michael@0 | 146 | * to paint the current color. Tragically this doesn't currently work with the |
michael@0 | 147 | * Quartz cairo backend which doesn't generally support masking with surfaces. |
michael@0 | 148 | * So for now we just paint a bunch of rectangles... |
michael@0 | 149 | */ |
michael@0 | 150 | #ifndef MOZ_GFX_OPTIMIZE_MOBILE |
michael@0 | 151 | static void |
michael@0 | 152 | DrawHexChar(gfxContext *aContext, const gfxPoint& aPt, uint32_t aDigit) |
michael@0 | 153 | { |
michael@0 | 154 | aContext->NewPath(); |
michael@0 | 155 | uint32_t glyphBits = glyphMicroFont[aDigit]; |
michael@0 | 156 | int x, y; |
michael@0 | 157 | for (y = 0; y < MINIFONT_HEIGHT; ++y) { |
michael@0 | 158 | for (x = 0; x < MINIFONT_WIDTH; ++x) { |
michael@0 | 159 | if (glyphBits & 1) { |
michael@0 | 160 | aContext->Rectangle(gfxRect(x, y, 1, 1) + aPt, true); |
michael@0 | 161 | } |
michael@0 | 162 | glyphBits >>= 1; |
michael@0 | 163 | } |
michael@0 | 164 | } |
michael@0 | 165 | aContext->Fill(); |
michael@0 | 166 | } |
michael@0 | 167 | #endif // MOZ_GFX_OPTIMIZE_MOBILE |
michael@0 | 168 | |
michael@0 | 169 | void |
michael@0 | 170 | gfxFontMissingGlyphs::DrawMissingGlyph(gfxContext *aContext, |
michael@0 | 171 | const gfxRect& aRect, |
michael@0 | 172 | uint32_t aChar, |
michael@0 | 173 | uint32_t aAppUnitsPerDevPixel) |
michael@0 | 174 | { |
michael@0 | 175 | aContext->Save(); |
michael@0 | 176 | |
michael@0 | 177 | gfxRGBA currentColor; |
michael@0 | 178 | if (!aContext->GetDeviceColor(currentColor)) { |
michael@0 | 179 | // We're currently drawing with some kind of pattern... Just draw |
michael@0 | 180 | // the missing-glyph data in black. |
michael@0 | 181 | currentColor = gfxRGBA(0,0,0,1); |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | // Stroke a rectangle so that the stroke's left edge is inset one pixel |
michael@0 | 185 | // from the left edge of the glyph box and the stroke's right edge |
michael@0 | 186 | // is inset one pixel from the right edge of the glyph box. |
michael@0 | 187 | gfxFloat halfBorderWidth = BOX_BORDER_WIDTH / 2.0; |
michael@0 | 188 | gfxFloat borderLeft = aRect.X() + BOX_HORIZONTAL_INSET + halfBorderWidth; |
michael@0 | 189 | gfxFloat borderRight = aRect.XMost() - BOX_HORIZONTAL_INSET - halfBorderWidth; |
michael@0 | 190 | gfxRect borderStrokeRect(borderLeft, aRect.Y() + halfBorderWidth, |
michael@0 | 191 | borderRight - borderLeft, |
michael@0 | 192 | aRect.Height() - 2.0 * halfBorderWidth); |
michael@0 | 193 | if (!borderStrokeRect.IsEmpty()) { |
michael@0 | 194 | aContext->SetLineWidth(BOX_BORDER_WIDTH); |
michael@0 | 195 | aContext->SetDash(gfxContext::gfxLineSolid); |
michael@0 | 196 | aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE); |
michael@0 | 197 | aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER); |
michael@0 | 198 | gfxRGBA color = currentColor; |
michael@0 | 199 | color.a *= BOX_BORDER_OPACITY; |
michael@0 | 200 | aContext->SetDeviceColor(color); |
michael@0 | 201 | aContext->NewPath(); |
michael@0 | 202 | aContext->Rectangle(borderStrokeRect); |
michael@0 | 203 | |
michael@0 | 204 | #ifdef MOZ_GFX_OPTIMIZE_MOBILE |
michael@0 | 205 | aContext->Fill(); |
michael@0 | 206 | #else |
michael@0 | 207 | aContext->Stroke(); |
michael@0 | 208 | #endif |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | #ifndef MOZ_GFX_OPTIMIZE_MOBILE |
michael@0 | 212 | gfxPoint center(aRect.X() + aRect.Width() / 2, |
michael@0 | 213 | aRect.Y() + aRect.Height() / 2); |
michael@0 | 214 | gfxFloat halfGap = HEX_CHAR_GAP / 2.0; |
michael@0 | 215 | gfxFloat top = -(MINIFONT_HEIGHT + halfGap); |
michael@0 | 216 | aContext->SetDeviceColor(currentColor); |
michael@0 | 217 | aContext->Translate(center); |
michael@0 | 218 | // We always want integer scaling, otherwise the "bitmap" glyphs will look |
michael@0 | 219 | // even uglier than usual when zoomed |
michael@0 | 220 | int32_t scale = |
michael@0 | 221 | std::max<int32_t>(1, nsDeviceContext::AppUnitsPerCSSPixel() / |
michael@0 | 222 | aAppUnitsPerDevPixel); |
michael@0 | 223 | aContext->Scale(gfxFloat(scale), gfxFloat(scale)); |
michael@0 | 224 | if (aChar < 0x10000) { |
michael@0 | 225 | if (aRect.Width() >= 2 * (MINIFONT_WIDTH + HEX_CHAR_GAP) && |
michael@0 | 226 | aRect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) { |
michael@0 | 227 | // Draw 4 digits for BMP |
michael@0 | 228 | gfxFloat left = -(MINIFONT_WIDTH + halfGap); |
michael@0 | 229 | DrawHexChar(aContext, |
michael@0 | 230 | gfxPoint(left, top), (aChar >> 12) & 0xF); |
michael@0 | 231 | DrawHexChar(aContext, |
michael@0 | 232 | gfxPoint(halfGap, top), (aChar >> 8) & 0xF); |
michael@0 | 233 | DrawHexChar(aContext, |
michael@0 | 234 | gfxPoint(left, halfGap), (aChar >> 4) & 0xF); |
michael@0 | 235 | DrawHexChar(aContext, |
michael@0 | 236 | gfxPoint(halfGap, halfGap), aChar & 0xF); |
michael@0 | 237 | } |
michael@0 | 238 | } else { |
michael@0 | 239 | if (aRect.Width() >= 3 * (MINIFONT_WIDTH + HEX_CHAR_GAP) && |
michael@0 | 240 | aRect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) { |
michael@0 | 241 | // Draw 6 digits for non-BMP |
michael@0 | 242 | gfxFloat first = -(MINIFONT_WIDTH * 1.5 + HEX_CHAR_GAP); |
michael@0 | 243 | gfxFloat second = -(MINIFONT_WIDTH / 2.0); |
michael@0 | 244 | gfxFloat third = (MINIFONT_WIDTH / 2.0 + HEX_CHAR_GAP); |
michael@0 | 245 | DrawHexChar(aContext, |
michael@0 | 246 | gfxPoint(first, top), (aChar >> 20) & 0xF); |
michael@0 | 247 | DrawHexChar(aContext, |
michael@0 | 248 | gfxPoint(second, top), (aChar >> 16) & 0xF); |
michael@0 | 249 | DrawHexChar(aContext, |
michael@0 | 250 | gfxPoint(third, top), (aChar >> 12) & 0xF); |
michael@0 | 251 | DrawHexChar(aContext, |
michael@0 | 252 | gfxPoint(first, halfGap), (aChar >> 8) & 0xF); |
michael@0 | 253 | DrawHexChar(aContext, |
michael@0 | 254 | gfxPoint(second, halfGap), (aChar >> 4) & 0xF); |
michael@0 | 255 | DrawHexChar(aContext, |
michael@0 | 256 | gfxPoint(third, halfGap), aChar & 0xF); |
michael@0 | 257 | } |
michael@0 | 258 | } |
michael@0 | 259 | #endif |
michael@0 | 260 | |
michael@0 | 261 | aContext->Restore(); |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | gfxFloat |
michael@0 | 265 | gfxFontMissingGlyphs::GetDesiredMinWidth(uint32_t aChar, |
michael@0 | 266 | uint32_t aAppUnitsPerDevPixel) |
michael@0 | 267 | { |
michael@0 | 268 | /** |
michael@0 | 269 | * The minimum desired width for a missing-glyph glyph box. I've laid it out |
michael@0 | 270 | * like this so you can see what goes where. |
michael@0 | 271 | */ |
michael@0 | 272 | gfxFloat width = BOX_HORIZONTAL_INSET + BOX_BORDER_WIDTH + HEX_CHAR_GAP + |
michael@0 | 273 | MINIFONT_WIDTH + HEX_CHAR_GAP + MINIFONT_WIDTH + |
michael@0 | 274 | ((aChar < 0x10000) ? 0 : HEX_CHAR_GAP + MINIFONT_WIDTH) + |
michael@0 | 275 | HEX_CHAR_GAP + BOX_BORDER_WIDTH + BOX_HORIZONTAL_INSET; |
michael@0 | 276 | // Note that this will give us floating-point division, so the width will |
michael@0 | 277 | // -not- be snapped to integer multiples of its basic pixel value |
michael@0 | 278 | width *= gfxFloat(nsDeviceContext::AppUnitsPerCSSPixel()) / aAppUnitsPerDevPixel; |
michael@0 | 279 | return width; |
michael@0 | 280 | } |