Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  gfxXlibSurface.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * 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/. */


#include "gfxXlibSurface.h"

#include "cairo.h"
#include "cairo-xlib.h"
#include <X11/Xlibint.h> /* For XESetCloseDisplay */
#undef max               // Xlibint.h defines this and it breaks std::max
#undef min               // Xlibint.h defines this and it breaks std::min
#undef Data

#include "nsTArray.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Preferences.h"
#include <algorithm>
#include "mozilla/CheckedInt.h"

using namespace mozilla;
using namespace mozilla::gfx;

gfxXlibSurface::gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual)
    : mPixmapTaken(false),
      mDisplay(XlibDisplay::Borrow(dpy)),
      mDrawable(drawable) {
  const gfx::IntSize size = DoSizeQuery();
  cairo_surface_t* surf =
      cairo_xlib_surface_create(dpy, drawable, visual, size.width, size.height);
  Init(surf);
}

gfxXlibSurface::gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual,
                               const gfx::IntSize& size)
    : gfxXlibSurface(XlibDisplay::Borrow(dpy), drawable, visual, size) {}

gfxXlibSurface::gfxXlibSurface(const std::shared_ptr<XlibDisplay>& dpy,
                               Drawable drawable, Visual* visual,
                               const gfx::IntSize& size)
    : mPixmapTaken(false), mDisplay(dpy), mDrawable(drawable) {
  NS_ASSERTION(Factory::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT),
               "Bad size");

  cairo_surface_t* surf = cairo_xlib_surface_create(*dpy, drawable, visual,
                                                    size.width, size.height);
  Init(surf);
}

gfxXlibSurface::gfxXlibSurface(cairo_surface_t* csurf) : mPixmapTaken(false) {
  MOZ_ASSERT(cairo_surface_status(csurf) == 0,
             "Not expecting an error surface");

  mDrawable = cairo_xlib_surface_get_drawable(csurf);
  mDisplay = XlibDisplay::Borrow(cairo_xlib_surface_get_display(csurf));

  Init(csurf, true);
}

gfxXlibSurface::~gfxXlibSurface() {
  // gfxASurface's destructor calls RecordMemoryFreed().
  if (mPixmapTaken) {
    XFreePixmap(*mDisplay, mDrawable);
  }
}

static Drawable CreatePixmap(Screen* screen, const gfx::IntSize& size,
                             unsigned int depth, Drawable relatedDrawable) {
  if (!Factory::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT))
    return X11None;

  if (relatedDrawable == X11None) {
    relatedDrawable = RootWindowOfScreen(screen);
  }
  Display* dpy = DisplayOfScreen(screen);
  // X gives us a fatal error if we try to create a pixmap of width
  // or height 0
  return XCreatePixmap(dpy, relatedDrawable, std::max(1, size.width),
                       std::max(1, size.height), depth);
}

void gfxXlibSurface::TakePixmap() {
  NS_ASSERTION(!mPixmapTaken, "I already own the Pixmap!");
  mPixmapTaken = true;

  // The bit depth returned from Cairo is technically int, but this is
  // the last place we'd be worried about that scenario.
  unsigned int bitDepth = cairo_xlib_surface_get_depth(CairoSurface());
  MOZ_ASSERT((bitDepth % 8) == 0, "Memory used not recorded correctly");

  // Divide by 8 because surface_get_depth gives us the number of *bits* per
  // pixel.
  gfx::IntSize size = GetSize();
  CheckedInt32 totalBytes =
      CheckedInt32(size.width) * CheckedInt32(size.height) * (bitDepth / 8);

  // Don't do anything in the "else" case.  We could add INT32_MAX, but that
  // would overflow the memory used counter.  It would also mean we tried for
  // a 2G image.  For now, we'll just assert,
  MOZ_ASSERT(totalBytes.isValid(), "Did not expect to exceed 2Gb image");
  if (totalBytes.isValid()) {
    RecordMemoryUsed(totalBytes.value());
  }
}

Drawable gfxXlibSurface::ReleasePixmap() {
  NS_ASSERTION(mPixmapTaken, "I don't own the Pixmap!");
  mPixmapTaken = false;
  RecordMemoryFreed();
  return mDrawable;
}

static cairo_user_data_key_t gDestroyPixmapKey;

struct DestroyPixmapClosure {
  DestroyPixmapClosure(Drawable d, Screen* s) : mPixmap(d), mScreen(s) {}
  Drawable mPixmap;
  Screen* mScreen;
};

static void DestroyPixmap(void* data) {
  DestroyPixmapClosure* closure = static_cast<DestroyPixmapClosure*>(data);
  XFreePixmap(DisplayOfScreen(closure->mScreen), closure->mPixmap);
  delete closure;
}

/* static */
cairo_surface_t* gfxXlibSurface::CreateCairoSurface(Screen* screen,
                                                    Visual* visual,
                                                    const gfx::IntSize& size,
                                                    Drawable relatedDrawable) {
  Drawable drawable = CreatePixmap(screen, size, DepthOfVisual(screen, visual),
                                   relatedDrawable);
  if (!drawable) return nullptr;

  cairo_surface_t* surface = cairo_xlib_surface_create(
      DisplayOfScreen(screen), drawable, visual, size.width, size.height);
  if (cairo_surface_status(surface)) {
    cairo_surface_destroy(surface);
    XFreePixmap(DisplayOfScreen(screen), drawable);
    return nullptr;
  }

  DestroyPixmapClosure* closure = new DestroyPixmapClosure(drawable, screen);
  cairo_surface_set_user_data(surface, &gDestroyPixmapKey, closure,
                              DestroyPixmap);
  return surface;
}

/* static */
already_AddRefed<gfxXlibSurface> gfxXlibSurface::Create(
    Screen* screen, Visual* visual, const gfx::IntSize& size,
    Drawable relatedDrawable) {
  return Create(XlibDisplay::Borrow(DisplayOfScreen(screen)), screen, visual,
                size, relatedDrawable);
};

/* static */
already_AddRefed<gfxXlibSurface> gfxXlibSurface::Create(
    const std::shared_ptr<XlibDisplay>& display, Screen* screen, Visual* visual,
    const gfx::IntSize& size, Drawable relatedDrawable) {
  MOZ_ASSERT(*display == DisplayOfScreen(screen));

  Drawable drawable = CreatePixmap(screen, size, DepthOfVisual(screen, visual),
                                   relatedDrawable);
  if (!drawable) return nullptr;

  RefPtr<gfxXlibSurface> result =
      new gfxXlibSurface(display, drawable, visual, size);
  result->TakePixmap();

  if (result->CairoStatus() != 0) return nullptr;

  return result.forget();
}

void gfxXlibSurface::Finish() { gfxASurface::Finish(); }

const gfx::IntSize gfxXlibSurface::GetSize() const {
  if (!mSurfaceValid) return gfx::IntSize(0, 0);

  return gfx::IntSize(cairo_xlib_surface_get_width(mSurface),
                      cairo_xlib_surface_get_height(mSurface));
}

const gfx::IntSize gfxXlibSurface::DoSizeQuery() {
  // figure out width/height/depth
  Window root_ignore;
  int x_ignore, y_ignore;
  unsigned int bwidth_ignore, width, height, depth;

  XGetGeometry(*mDisplay, mDrawable, &root_ignore, &x_ignore, &y_ignore, &width,
               &height, &bwidth_ignore, &depth);

  return gfx::IntSize(width, height);
}

class DisplayTable {
 public:
  static bool GetColormapAndVisual(Screen* screen, Visual* visual,
                                   Colormap* colormap,
                                   Visual** visualForColormap);

 private:
  struct ColormapEntry {
    // The Screen is needed here because colormaps (and their visuals) may
    // only be used on one Screen
    Screen* mScreen;
    Visual* mVisual;
    Colormap mColormap;
  };

  class DisplayInfo {
   public:
    explicit DisplayInfo(Display* display) : mDisplay(display) {}
    Display* mDisplay;
    nsTArray<ColormapEntry> mColormapEntries;
  };

  // Comparator for finding the DisplayInfo
  class FindDisplay {
   public:
    bool Equals(const DisplayInfo& info, const Display* display) const {
      return info.mDisplay == display;
    }
  };

  static int DisplayClosing(Display* display, XExtCodes* codes);

  nsTArray<DisplayInfo> mDisplays;
  static DisplayTable* sDisplayTable;
};

DisplayTable* DisplayTable::sDisplayTable;

// Pixmaps don't have a particular associated visual but the pixel values are
// interpreted according to a visual/colormap pairs.
//
// cairo is designed for surfaces with either TrueColor visuals or the
// default visual (which may not be true color).  TrueColor visuals don't
// really need a colormap because the visual indicates the pixel format,
// and cairo uses the default visual with the default colormap, so cairo
// surfaces don't need an explicit colormap.
//
// However, some toolkits (e.g. GDK) need a colormap even with TrueColor
// visuals.  We can create a colormap for these visuals, but it will use about
// 20kB of memory in the server, so we use the default colormap when
// suitable and share colormaps between surfaces.  Another reason for
// minimizing colormap turnover is that the plugin process must leak resources
// for each new colormap id when using older GDK libraries (bug 569775).
//
// Only the format of the pixels is important for rendering to Pixmaps, so if
// the format of a visual matches that of the surface, then that visual can be
// used for rendering to the surface.  Multiple visuals can match the same
// format (but have different GLX properties), so the visual returned may
// differ from the visual passed in.  Colormaps are tied to a visual, so
// should only be used with their visual.

/* static */
bool DisplayTable::GetColormapAndVisual(Screen* aScreen, Visual* aVisual,
                                        Colormap* aColormap,
                                        Visual** aVisualForColormap)

{
  Display* display = DisplayOfScreen(aScreen);

  // Use the default colormap if the default visual matches.
  Visual* defaultVisual = DefaultVisualOfScreen(aScreen);
  if (aVisual == defaultVisual) {
    *aColormap = DefaultColormapOfScreen(aScreen);
    *aVisualForColormap = defaultVisual;
    return true;
  }

  // Only supporting TrueColor non-default visuals
  if (!aVisual || aVisual->c_class != TrueColor) return false;

  if (!sDisplayTable) {
    sDisplayTable = new DisplayTable();
  }

  nsTArray<DisplayInfo>* displays = &sDisplayTable->mDisplays;
  size_t d = displays->IndexOf(display, 0, FindDisplay());

  if (d == displays->NoIndex) {
    d = displays->Length();
    // Register for notification of display closing, when this info
    // becomes invalid.
    XExtCodes* codes = XAddExtension(display);
    if (!codes) return false;

    XESetCloseDisplay(display, codes->extension, DisplayClosing);
    // Add a new DisplayInfo.
    displays->AppendElement(display);
  }

  nsTArray<ColormapEntry>* entries = &displays->ElementAt(d).mColormapEntries;

  // Only a small number of formats are expected to be used, so just do a
  // simple linear search.
  for (uint32_t i = 0; i < entries->Length(); ++i) {
    const ColormapEntry& entry = entries->ElementAt(i);
    if (aVisual == entry.mVisual) {
      *aColormap = entry.mColormap;
      *aVisualForColormap = entry.mVisual;
      return true;
    }
  }

  // No existing entry.  Create a colormap and add an entry.
  Colormap colormap =
      XCreateColormap(display, RootWindowOfScreen(aScreen), aVisual, AllocNone);
  ColormapEntry* newEntry = entries->AppendElement();
  newEntry->mScreen = aScreen;
  newEntry->mVisual = aVisual;
  newEntry->mColormap = colormap;

  *aColormap = colormap;
  *aVisualForColormap = aVisual;
  return true;
}

/* static */
int DisplayTable::DisplayClosing(Display* display, XExtCodes* codes) {
  // No need to free the colormaps explicitly as they will be released when
  // the connection is closed.
  sDisplayTable->mDisplays.RemoveElement(display, FindDisplay());
  if (sDisplayTable->mDisplays.Length() == 0) {
    delete sDisplayTable;
    sDisplayTable = nullptr;
  }
  return 0;
}

/* static */
bool gfxXlibSurface::GetColormapAndVisual(cairo_surface_t* aXlibSurface,
                                          Colormap* aColormap,
                                          Visual** aVisual) {
  Screen* screen = cairo_xlib_surface_get_screen(aXlibSurface);
  Visual* visual = cairo_xlib_surface_get_visual(aXlibSurface);

  return DisplayTable::GetColormapAndVisual(screen, visual, aColormap, aVisual);
}

bool gfxXlibSurface::GetColormapAndVisual(Colormap* aColormap,
                                          Visual** aVisual) {
  if (!mSurfaceValid) return false;

  return GetColormapAndVisual(CairoSurface(), aColormap, aVisual);
}

/* static */
int gfxXlibSurface::DepthOfVisual(const Screen* screen, const Visual* visual) {
  for (int d = 0; d < screen->ndepths; d++) {
    const Depth& d_info = screen->depths[d];
    if (visual >= &d_info.visuals[0] &&
        visual < &d_info.visuals[d_info.nvisuals])
      return d_info.depth;
  }

  NS_ERROR("Visual not on Screen.");
  return 0;
}

/* static */
Visual* gfxXlibSurface::FindVisual(Screen* screen, gfxImageFormat format) {
  int depth;
  unsigned long red_mask, green_mask, blue_mask;
  switch (format) {
    case gfx::SurfaceFormat::A8R8G8B8_UINT32:
      depth = 32;
      red_mask = 0xff0000;
      green_mask = 0xff00;
      blue_mask = 0xff;
      break;
    case gfx::SurfaceFormat::X8R8G8B8_UINT32:
      depth = 24;
      red_mask = 0xff0000;
      green_mask = 0xff00;
      blue_mask = 0xff;
      break;
    case gfx::SurfaceFormat::R5G6B5_UINT16:
      depth = 16;
      red_mask = 0xf800;
      green_mask = 0x7e0;
      blue_mask = 0x1f;
      break;
    case gfx::SurfaceFormat::A8:
    default:
      return nullptr;
  }

  for (int d = 0; d < screen->ndepths; d++) {
    const Depth& d_info = screen->depths[d];
    if (d_info.depth != depth) continue;

    for (int v = 0; v < d_info.nvisuals; v++) {
      Visual* visual = &d_info.visuals[v];

      if (visual->c_class == TrueColor && visual->red_mask == red_mask &&
          visual->green_mask == green_mask && visual->blue_mask == blue_mask)
        return visual;
    }
  }

  return nullptr;
}

Screen* gfxXlibSurface::XScreen() {
  return cairo_xlib_surface_get_screen(CairoSurface());
}

95%


¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge