DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _MOZILLA_GFX_SKIACGPOPUPDRAWER_H
#define _MOZILLA_GFX_SKIACGPOPUPDRAWER_H

#include <ApplicationServices/ApplicationServices.h>
#include "nsDebug.h"
#include "mozilla/Vector.h"
#include "ScaledFontMac.h"
#include <dlfcn.h>

// This is used when we explicitly need CG to draw text to support things such
// as vibrancy and subpixel AA on transparent backgrounds. The current use cases
// are really only to enable Skia to support drawing text in those situations.

namespace mozilla {
namespace gfx {

typedef void (*CGContextSetFontSmoothingBackgroundColorFunc)(CGContextRef cgContext,
                                                             CGColorRef color);

static CGContextSetFontSmoothingBackgroundColorFunc
GetCGContextSetFontSmoothingBackgroundColorFunc() {
  static CGContextSetFontSmoothingBackgroundColorFunc func = nullptr;
  static bool lookedUpFunc = false;
  if (!lookedUpFunc) {
    func = (CGContextSetFontSmoothingBackgroundColorFunc)dlsym(
        RTLD_DEFAULT, "CGContextSetFontSmoothingBackgroundColor");
    lookedUpFunc = true;
  }
  return func;
}

static CGColorRef ColorToCGColor(CGColorSpaceRef aColorSpace, const Color& aColor) {
  CGFloat components[4] = {aColor.r, aColor.g, aColor.b, aColor.a};
  return CGColorCreate(aColorSpace, components);
}

static bool SetFontSmoothingBackgroundColor(CGContextRef aCGContext, CGColorSpaceRef aColorSpace,
                                            const Color& aFontSmoothingBackgroundColor) {
  if (aFontSmoothingBackgroundColor.a > 0) {
    CGContextSetFontSmoothingBackgroundColorFunc setFontSmoothingBGColorFunc =
        GetCGContextSetFontSmoothingBackgroundColorFunc();
    if (setFontSmoothingBGColorFunc) {
      CGColorRef color = ColorToCGColor(aColorSpace, aFontSmoothingBackgroundColor);
      setFontSmoothingBGColorFunc(aCGContext, color);
      CGColorRelease(color);
      return true;
    }
  }

  return false;
}

// Font rendering with a non-transparent font smoothing background color
// can leave pixels in our buffer where the rgb components exceed the alpha
// component. When this happens we need to clean up the data afterwards.
// The purpose of this is probably the following: Correct compositing of
// subpixel anti-aliased fonts on transparent backgrounds requires
// different alpha values per RGB component. Usually, premultiplied color
// values are derived by multiplying all components with the same per-pixel
// alpha value. However, if you multiply each component with a *different*
// alpha, and set the alpha component of the pixel to, say, the average
// of the alpha values that you used during the premultiplication of the
// RGB components, you can trick OVER compositing into doing a simplified
// form of component alpha compositing. (You just need to make sure to
// clamp the components of the result pixel to [0,255] afterwards.)
static void EnsureValidPremultipliedData(CGContextRef aContext,
                                         CGRect aTextBounds = CGRectInfinite) {
  if (CGBitmapContextGetBitsPerPixel(aContext) != 32 ||
      CGBitmapContextGetAlphaInfo(aContext) != kCGImageAlphaPremultipliedFirst) {
    return;
  }

  uint8_t* bitmapData = (uint8_t*)CGBitmapContextGetData(aContext);
  CGRect bitmapBounds =
      CGRectMake(0, 0, CGBitmapContextGetWidth(aContext), CGBitmapContextGetHeight(aContext));
  int stride = CGBitmapContextGetBytesPerRow(aContext);

  CGRect bounds = CGRectIntersection(bitmapBounds, aTextBounds);
  int startX = bounds.origin.x;
  int endX = startX + bounds.size.width;
  MOZ_ASSERT(endX <= bitmapBounds.size.width);

  // CGRect assume that our origin is the bottom left.
  // The data assumes that the origin is the top left.
  // Have to switch the Y axis so that our coordinates are correct
  int startY = bitmapBounds.size.height - (bounds.origin.y + bounds.size.height);
  int endY = startY + bounds.size.height;
  MOZ_ASSERT(endY <= (int)CGBitmapContextGetHeight(aContext));

  for (int y = startY; y < endY; y++) {
    for (int x = startX; x < endX; x++) {
      int i = y * stride + x * 4;
      uint8_t a = bitmapData[i + 3];

      bitmapData[i + 0] = std::min(a, bitmapData[i + 0]);
      bitmapData[i + 1] = std::min(a, bitmapData[i + 1]);
      bitmapData[i + 2] = std::min(a, bitmapData[i + 2]);
    }
  }
}

static CGRect ComputeGlyphsExtents(CGRect* bboxes, CGPoint* positions, CFIndex count, float scale) {
  CGFloat x1, x2, y1, y2;
  if (count < 1) return CGRectZero;

  x1 = bboxes[0].origin.x + positions[0].x;
  x2 = bboxes[0].origin.x + positions[0].x + scale * bboxes[0].size.width;
  y1 = bboxes[0].origin.y + positions[0].y;
  y2 = bboxes[0].origin.y + positions[0].y + scale * bboxes[0].size.height;

  // accumulate max and minimum coordinates
  for (int i = 1; i < count; i++) {
    x1 = std::min(x1, bboxes[i].origin.x + positions[i].x);
    y1 = std::min(y1, bboxes[i].origin.y + positions[i].y);
    x2 = std::max(x2, bboxes[i].origin.x + positions[i].x + scale * bboxes[i].size.width);
    y2 = std::max(y2, bboxes[i].origin.y + positions[i].y + scale * bboxes[i].size.height);
  }

  CGRect extents = {{x1, y1}, {x2 - x1, y2 - y1}};
  return extents;
}

}  // namespace gfx
}  // namespace mozilla

#endif