gfx/thebes/gfxFontMissingGlyphs.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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 }

mercurial