Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "gfxXlibSurface.h" |
michael@0 | 7 | |
michael@0 | 8 | #include "cairo.h" |
michael@0 | 9 | #include "cairo-xlib.h" |
michael@0 | 10 | #include "cairo-xlib-xrender.h" |
michael@0 | 11 | #include <X11/Xlibint.h> /* For XESetCloseDisplay */ |
michael@0 | 12 | #undef max // Xlibint.h defines this and it breaks std::max |
michael@0 | 13 | #undef min // Xlibint.h defines this and it breaks std::min |
michael@0 | 14 | |
michael@0 | 15 | #include "nsAutoPtr.h" |
michael@0 | 16 | #include "nsTArray.h" |
michael@0 | 17 | #include "nsAlgorithm.h" |
michael@0 | 18 | #include "mozilla/Preferences.h" |
michael@0 | 19 | #include <algorithm> |
michael@0 | 20 | #include "mozilla/CheckedInt.h" |
michael@0 | 21 | |
michael@0 | 22 | using namespace mozilla; |
michael@0 | 23 | |
michael@0 | 24 | // Although the dimension parameters in the xCreatePixmapReq wire protocol are |
michael@0 | 25 | // 16-bit unsigned integers, the server's CreatePixmap returns BadAlloc if |
michael@0 | 26 | // either dimension cannot be represented by a 16-bit *signed* integer. |
michael@0 | 27 | #define XLIB_IMAGE_SIDE_SIZE_LIMIT 0x7fff |
michael@0 | 28 | |
michael@0 | 29 | gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual) |
michael@0 | 30 | : mPixmapTaken(false), mDisplay(dpy), mDrawable(drawable) |
michael@0 | 31 | #if defined(GL_PROVIDER_GLX) |
michael@0 | 32 | , mGLXPixmap(None) |
michael@0 | 33 | #endif |
michael@0 | 34 | { |
michael@0 | 35 | const gfxIntSize size = DoSizeQuery(); |
michael@0 | 36 | cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, size.width, size.height); |
michael@0 | 37 | Init(surf); |
michael@0 | 38 | } |
michael@0 | 39 | |
michael@0 | 40 | gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual, const gfxIntSize& size) |
michael@0 | 41 | : mPixmapTaken(false), mDisplay(dpy), mDrawable(drawable) |
michael@0 | 42 | #if defined(GL_PROVIDER_GLX) |
michael@0 | 43 | , mGLXPixmap(None) |
michael@0 | 44 | #endif |
michael@0 | 45 | { |
michael@0 | 46 | NS_ASSERTION(CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT), |
michael@0 | 47 | "Bad size"); |
michael@0 | 48 | |
michael@0 | 49 | cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, size.width, size.height); |
michael@0 | 50 | Init(surf); |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | gfxXlibSurface::gfxXlibSurface(Screen *screen, Drawable drawable, XRenderPictFormat *format, |
michael@0 | 54 | const gfxIntSize& size) |
michael@0 | 55 | : mPixmapTaken(false), mDisplay(DisplayOfScreen(screen)), |
michael@0 | 56 | mDrawable(drawable) |
michael@0 | 57 | #if defined(GL_PROVIDER_GLX) |
michael@0 | 58 | , mGLXPixmap(None) |
michael@0 | 59 | #endif |
michael@0 | 60 | { |
michael@0 | 61 | NS_ASSERTION(CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT), |
michael@0 | 62 | "Bad Size"); |
michael@0 | 63 | |
michael@0 | 64 | cairo_surface_t *surf = |
michael@0 | 65 | cairo_xlib_surface_create_with_xrender_format(mDisplay, drawable, |
michael@0 | 66 | screen, format, |
michael@0 | 67 | size.width, size.height); |
michael@0 | 68 | Init(surf); |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | gfxXlibSurface::gfxXlibSurface(cairo_surface_t *csurf) |
michael@0 | 72 | : mPixmapTaken(false) |
michael@0 | 73 | #if defined(GL_PROVIDER_GLX) |
michael@0 | 74 | , mGLXPixmap(None) |
michael@0 | 75 | #endif |
michael@0 | 76 | { |
michael@0 | 77 | NS_PRECONDITION(cairo_surface_status(csurf) == 0, |
michael@0 | 78 | "Not expecting an error surface"); |
michael@0 | 79 | |
michael@0 | 80 | mDrawable = cairo_xlib_surface_get_drawable(csurf); |
michael@0 | 81 | mDisplay = cairo_xlib_surface_get_display(csurf); |
michael@0 | 82 | |
michael@0 | 83 | Init(csurf, true); |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | gfxXlibSurface::~gfxXlibSurface() |
michael@0 | 87 | { |
michael@0 | 88 | #if defined(GL_PROVIDER_GLX) |
michael@0 | 89 | if (mGLXPixmap) { |
michael@0 | 90 | gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap); |
michael@0 | 91 | } |
michael@0 | 92 | #endif |
michael@0 | 93 | // gfxASurface's destructor calls RecordMemoryFreed(). |
michael@0 | 94 | if (mPixmapTaken) { |
michael@0 | 95 | XFreePixmap (mDisplay, mDrawable); |
michael@0 | 96 | } |
michael@0 | 97 | } |
michael@0 | 98 | |
michael@0 | 99 | static Drawable |
michael@0 | 100 | CreatePixmap(Screen *screen, const gfxIntSize& size, unsigned int depth, |
michael@0 | 101 | Drawable relatedDrawable) |
michael@0 | 102 | { |
michael@0 | 103 | if (!gfxASurface::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT)) |
michael@0 | 104 | return None; |
michael@0 | 105 | |
michael@0 | 106 | if (relatedDrawable == None) { |
michael@0 | 107 | relatedDrawable = RootWindowOfScreen(screen); |
michael@0 | 108 | } |
michael@0 | 109 | Display *dpy = DisplayOfScreen(screen); |
michael@0 | 110 | // X gives us a fatal error if we try to create a pixmap of width |
michael@0 | 111 | // or height 0 |
michael@0 | 112 | return XCreatePixmap(dpy, relatedDrawable, |
michael@0 | 113 | std::max(1, size.width), std::max(1, size.height), |
michael@0 | 114 | depth); |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | void |
michael@0 | 118 | gfxXlibSurface::TakePixmap() |
michael@0 | 119 | { |
michael@0 | 120 | NS_ASSERTION(!mPixmapTaken, "I already own the Pixmap!"); |
michael@0 | 121 | mPixmapTaken = true; |
michael@0 | 122 | |
michael@0 | 123 | // The bit depth returned from Cairo is technically int, but this is |
michael@0 | 124 | // the last place we'd be worried about that scenario. |
michael@0 | 125 | unsigned int bitDepth = cairo_xlib_surface_get_depth(CairoSurface()); |
michael@0 | 126 | MOZ_ASSERT((bitDepth % 8) == 0, "Memory used not recorded correctly"); |
michael@0 | 127 | |
michael@0 | 128 | // Divide by 8 because surface_get_depth gives us the number of *bits* per |
michael@0 | 129 | // pixel. |
michael@0 | 130 | gfxIntSize size = GetSize(); |
michael@0 | 131 | CheckedInt32 totalBytes = CheckedInt32(size.width) * CheckedInt32(size.height) * (bitDepth/8); |
michael@0 | 132 | |
michael@0 | 133 | // Don't do anything in the "else" case. We could add INT32_MAX, but that |
michael@0 | 134 | // would overflow the memory used counter. It would also mean we tried for |
michael@0 | 135 | // a 2G image. For now, we'll just assert, |
michael@0 | 136 | MOZ_ASSERT(totalBytes.isValid(),"Did not expect to exceed 2Gb image"); |
michael@0 | 137 | if (totalBytes.isValid()) { |
michael@0 | 138 | RecordMemoryUsed(totalBytes.value()); |
michael@0 | 139 | } |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | Drawable |
michael@0 | 143 | gfxXlibSurface::ReleasePixmap() { |
michael@0 | 144 | NS_ASSERTION(mPixmapTaken, "I don't own the Pixmap!"); |
michael@0 | 145 | mPixmapTaken = false; |
michael@0 | 146 | RecordMemoryFreed(); |
michael@0 | 147 | return mDrawable; |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | static cairo_user_data_key_t gDestroyPixmapKey; |
michael@0 | 151 | |
michael@0 | 152 | struct DestroyPixmapClosure { |
michael@0 | 153 | DestroyPixmapClosure(Drawable d, Screen *s) : mPixmap(d), mScreen(s) {} |
michael@0 | 154 | Drawable mPixmap; |
michael@0 | 155 | Screen *mScreen; |
michael@0 | 156 | }; |
michael@0 | 157 | |
michael@0 | 158 | static void |
michael@0 | 159 | DestroyPixmap(void *data) |
michael@0 | 160 | { |
michael@0 | 161 | DestroyPixmapClosure *closure = static_cast<DestroyPixmapClosure*>(data); |
michael@0 | 162 | XFreePixmap(DisplayOfScreen(closure->mScreen), closure->mPixmap); |
michael@0 | 163 | delete closure; |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | /* static */ |
michael@0 | 167 | cairo_surface_t * |
michael@0 | 168 | gfxXlibSurface::CreateCairoSurface(Screen *screen, Visual *visual, |
michael@0 | 169 | const gfxIntSize& size, Drawable relatedDrawable) |
michael@0 | 170 | { |
michael@0 | 171 | Drawable drawable = |
michael@0 | 172 | CreatePixmap(screen, size, DepthOfVisual(screen, visual), |
michael@0 | 173 | relatedDrawable); |
michael@0 | 174 | if (!drawable) |
michael@0 | 175 | return nullptr; |
michael@0 | 176 | |
michael@0 | 177 | cairo_surface_t* surface = |
michael@0 | 178 | cairo_xlib_surface_create(DisplayOfScreen(screen), drawable, visual, |
michael@0 | 179 | size.width, size.height); |
michael@0 | 180 | if (cairo_surface_status(surface)) { |
michael@0 | 181 | cairo_surface_destroy(surface); |
michael@0 | 182 | XFreePixmap(DisplayOfScreen(screen), drawable); |
michael@0 | 183 | return nullptr; |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | DestroyPixmapClosure *closure = new DestroyPixmapClosure(drawable, screen); |
michael@0 | 187 | cairo_surface_set_user_data(surface, &gDestroyPixmapKey, |
michael@0 | 188 | closure, DestroyPixmap); |
michael@0 | 189 | return surface; |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | /* static */ |
michael@0 | 193 | already_AddRefed<gfxXlibSurface> |
michael@0 | 194 | gfxXlibSurface::Create(Screen *screen, Visual *visual, |
michael@0 | 195 | const gfxIntSize& size, Drawable relatedDrawable) |
michael@0 | 196 | { |
michael@0 | 197 | Drawable drawable = |
michael@0 | 198 | CreatePixmap(screen, size, DepthOfVisual(screen, visual), |
michael@0 | 199 | relatedDrawable); |
michael@0 | 200 | if (!drawable) |
michael@0 | 201 | return nullptr; |
michael@0 | 202 | |
michael@0 | 203 | nsRefPtr<gfxXlibSurface> result = |
michael@0 | 204 | new gfxXlibSurface(DisplayOfScreen(screen), drawable, visual, size); |
michael@0 | 205 | result->TakePixmap(); |
michael@0 | 206 | |
michael@0 | 207 | if (result->CairoStatus() != 0) |
michael@0 | 208 | return nullptr; |
michael@0 | 209 | |
michael@0 | 210 | return result.forget(); |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | /* static */ |
michael@0 | 214 | already_AddRefed<gfxXlibSurface> |
michael@0 | 215 | gfxXlibSurface::Create(Screen *screen, XRenderPictFormat *format, |
michael@0 | 216 | const gfxIntSize& size, Drawable relatedDrawable) |
michael@0 | 217 | { |
michael@0 | 218 | Drawable drawable = |
michael@0 | 219 | CreatePixmap(screen, size, format->depth, relatedDrawable); |
michael@0 | 220 | if (!drawable) |
michael@0 | 221 | return nullptr; |
michael@0 | 222 | |
michael@0 | 223 | nsRefPtr<gfxXlibSurface> result = |
michael@0 | 224 | new gfxXlibSurface(screen, drawable, format, size); |
michael@0 | 225 | result->TakePixmap(); |
michael@0 | 226 | |
michael@0 | 227 | if (result->CairoStatus() != 0) |
michael@0 | 228 | return nullptr; |
michael@0 | 229 | |
michael@0 | 230 | return result.forget(); |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | static bool GetForce24bppPref() |
michael@0 | 234 | { |
michael@0 | 235 | return Preferences::GetBool("mozilla.widget.force-24bpp", false); |
michael@0 | 236 | } |
michael@0 | 237 | |
michael@0 | 238 | already_AddRefed<gfxASurface> |
michael@0 | 239 | gfxXlibSurface::CreateSimilarSurface(gfxContentType aContent, |
michael@0 | 240 | const gfxIntSize& aSize) |
michael@0 | 241 | { |
michael@0 | 242 | if (!mSurface || !mSurfaceValid) { |
michael@0 | 243 | return nullptr; |
michael@0 | 244 | } |
michael@0 | 245 | |
michael@0 | 246 | if (aContent == gfxContentType::COLOR) { |
michael@0 | 247 | // cairo_surface_create_similar will use a matching visual if it can. |
michael@0 | 248 | // However, systems with 16-bit or indexed default visuals may benefit |
michael@0 | 249 | // from rendering with 24-bit formats. |
michael@0 | 250 | static bool force24bpp = GetForce24bppPref(); |
michael@0 | 251 | if (force24bpp |
michael@0 | 252 | && cairo_xlib_surface_get_depth(CairoSurface()) != 24) { |
michael@0 | 253 | XRenderPictFormat* format = |
michael@0 | 254 | XRenderFindStandardFormat(mDisplay, PictStandardRGB24); |
michael@0 | 255 | if (format) { |
michael@0 | 256 | // Cairo only performs simple self-copies as desired if it |
michael@0 | 257 | // knows that this is a Pixmap surface. It only knows that |
michael@0 | 258 | // surfaces are pixmap surfaces if it creates the Pixmap |
michael@0 | 259 | // itself, so we use cairo_surface_create_similar with a |
michael@0 | 260 | // temporary reference surface to indicate the format. |
michael@0 | 261 | Screen* screen = cairo_xlib_surface_get_screen(CairoSurface()); |
michael@0 | 262 | nsRefPtr<gfxXlibSurface> depth24reference = |
michael@0 | 263 | gfxXlibSurface::Create(screen, format, |
michael@0 | 264 | gfxIntSize(1, 1), mDrawable); |
michael@0 | 265 | if (depth24reference) |
michael@0 | 266 | return depth24reference-> |
michael@0 | 267 | gfxASurface::CreateSimilarSurface(aContent, aSize); |
michael@0 | 268 | } |
michael@0 | 269 | } |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | return gfxASurface::CreateSimilarSurface(aContent, aSize); |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | void |
michael@0 | 276 | gfxXlibSurface::Finish() |
michael@0 | 277 | { |
michael@0 | 278 | #if defined(GL_PROVIDER_GLX) |
michael@0 | 279 | if (mGLXPixmap) { |
michael@0 | 280 | gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap); |
michael@0 | 281 | mGLXPixmap = None; |
michael@0 | 282 | } |
michael@0 | 283 | #endif |
michael@0 | 284 | gfxASurface::Finish(); |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | const gfxIntSize |
michael@0 | 288 | gfxXlibSurface::GetSize() const |
michael@0 | 289 | { |
michael@0 | 290 | if (!mSurfaceValid) |
michael@0 | 291 | return gfxIntSize(0,0); |
michael@0 | 292 | |
michael@0 | 293 | return gfxIntSize(cairo_xlib_surface_get_width(mSurface), |
michael@0 | 294 | cairo_xlib_surface_get_height(mSurface)); |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | const gfxIntSize |
michael@0 | 298 | gfxXlibSurface::DoSizeQuery() |
michael@0 | 299 | { |
michael@0 | 300 | // figure out width/height/depth |
michael@0 | 301 | Window root_ignore; |
michael@0 | 302 | int x_ignore, y_ignore; |
michael@0 | 303 | unsigned int bwidth_ignore, width, height, depth; |
michael@0 | 304 | |
michael@0 | 305 | XGetGeometry(mDisplay, |
michael@0 | 306 | mDrawable, |
michael@0 | 307 | &root_ignore, &x_ignore, &y_ignore, |
michael@0 | 308 | &width, &height, |
michael@0 | 309 | &bwidth_ignore, &depth); |
michael@0 | 310 | |
michael@0 | 311 | return gfxIntSize(width, height); |
michael@0 | 312 | } |
michael@0 | 313 | |
michael@0 | 314 | class DisplayTable { |
michael@0 | 315 | public: |
michael@0 | 316 | static bool GetColormapAndVisual(Screen* screen, |
michael@0 | 317 | XRenderPictFormat* format, |
michael@0 | 318 | Visual* visual, Colormap* colormap, |
michael@0 | 319 | Visual** visualForColormap); |
michael@0 | 320 | |
michael@0 | 321 | private: |
michael@0 | 322 | struct ColormapEntry { |
michael@0 | 323 | XRenderPictFormat* mFormat; |
michael@0 | 324 | // The Screen is needed here because colormaps (and their visuals) may |
michael@0 | 325 | // only be used on one Screen, but XRenderPictFormats are not unique |
michael@0 | 326 | // to any one Screen. |
michael@0 | 327 | Screen* mScreen; |
michael@0 | 328 | Visual* mVisual; |
michael@0 | 329 | Colormap mColormap; |
michael@0 | 330 | }; |
michael@0 | 331 | |
michael@0 | 332 | class DisplayInfo { |
michael@0 | 333 | public: |
michael@0 | 334 | DisplayInfo(Display* display) : mDisplay(display) { } |
michael@0 | 335 | Display* mDisplay; |
michael@0 | 336 | nsTArray<ColormapEntry> mColormapEntries; |
michael@0 | 337 | }; |
michael@0 | 338 | |
michael@0 | 339 | // Comparator for finding the DisplayInfo |
michael@0 | 340 | class FindDisplay { |
michael@0 | 341 | public: |
michael@0 | 342 | bool Equals(const DisplayInfo& info, const Display *display) const |
michael@0 | 343 | { |
michael@0 | 344 | return info.mDisplay == display; |
michael@0 | 345 | } |
michael@0 | 346 | }; |
michael@0 | 347 | |
michael@0 | 348 | static int DisplayClosing(Display *display, XExtCodes* codes); |
michael@0 | 349 | |
michael@0 | 350 | nsTArray<DisplayInfo> mDisplays; |
michael@0 | 351 | static DisplayTable* sDisplayTable; |
michael@0 | 352 | }; |
michael@0 | 353 | |
michael@0 | 354 | DisplayTable* DisplayTable::sDisplayTable; |
michael@0 | 355 | |
michael@0 | 356 | // Pixmaps don't have a particular associated visual but the pixel values are |
michael@0 | 357 | // interpreted according to a visual/colormap pairs. |
michael@0 | 358 | // |
michael@0 | 359 | // cairo is designed for surfaces with either TrueColor visuals or the |
michael@0 | 360 | // default visual (which may not be true color). TrueColor visuals don't |
michael@0 | 361 | // really need a colormap because the visual indicates the pixel format, |
michael@0 | 362 | // and cairo uses the default visual with the default colormap, so cairo |
michael@0 | 363 | // surfaces don't need an explicit colormap. |
michael@0 | 364 | // |
michael@0 | 365 | // However, some toolkits (e.g. GDK) need a colormap even with TrueColor |
michael@0 | 366 | // visuals. We can create a colormap for these visuals, but it will use about |
michael@0 | 367 | // 20kB of memory in the server, so we use the default colormap when |
michael@0 | 368 | // suitable and share colormaps between surfaces. Another reason for |
michael@0 | 369 | // minimizing colormap turnover is that the plugin process must leak resources |
michael@0 | 370 | // for each new colormap id when using older GDK libraries (bug 569775). |
michael@0 | 371 | // |
michael@0 | 372 | // Only the format of the pixels is important for rendering to Pixmaps, so if |
michael@0 | 373 | // the format of a visual matches that of the surface, then that visual can be |
michael@0 | 374 | // used for rendering to the surface. Multiple visuals can match the same |
michael@0 | 375 | // format (but have different GLX properties), so the visual returned may |
michael@0 | 376 | // differ from the visual passed in. Colormaps are tied to a visual, so |
michael@0 | 377 | // should only be used with their visual. |
michael@0 | 378 | |
michael@0 | 379 | /* static */ bool |
michael@0 | 380 | DisplayTable::GetColormapAndVisual(Screen* aScreen, XRenderPictFormat* aFormat, |
michael@0 | 381 | Visual* aVisual, Colormap* aColormap, |
michael@0 | 382 | Visual** aVisualForColormap) |
michael@0 | 383 | |
michael@0 | 384 | { |
michael@0 | 385 | Display* display = DisplayOfScreen(aScreen); |
michael@0 | 386 | |
michael@0 | 387 | // Use the default colormap if the default visual matches. |
michael@0 | 388 | Visual *defaultVisual = DefaultVisualOfScreen(aScreen); |
michael@0 | 389 | if (aVisual == defaultVisual |
michael@0 | 390 | || (aFormat |
michael@0 | 391 | && aFormat == XRenderFindVisualFormat(display, defaultVisual))) |
michael@0 | 392 | { |
michael@0 | 393 | *aColormap = DefaultColormapOfScreen(aScreen); |
michael@0 | 394 | *aVisualForColormap = defaultVisual; |
michael@0 | 395 | return true; |
michael@0 | 396 | } |
michael@0 | 397 | |
michael@0 | 398 | // Only supporting TrueColor non-default visuals |
michael@0 | 399 | if (!aVisual || aVisual->c_class != TrueColor) |
michael@0 | 400 | return false; |
michael@0 | 401 | |
michael@0 | 402 | if (!sDisplayTable) { |
michael@0 | 403 | sDisplayTable = new DisplayTable(); |
michael@0 | 404 | } |
michael@0 | 405 | |
michael@0 | 406 | nsTArray<DisplayInfo>* displays = &sDisplayTable->mDisplays; |
michael@0 | 407 | uint32_t d = displays->IndexOf(display, 0, FindDisplay()); |
michael@0 | 408 | |
michael@0 | 409 | if (d == displays->NoIndex) { |
michael@0 | 410 | d = displays->Length(); |
michael@0 | 411 | // Register for notification of display closing, when this info |
michael@0 | 412 | // becomes invalid. |
michael@0 | 413 | XExtCodes *codes = XAddExtension(display); |
michael@0 | 414 | if (!codes) |
michael@0 | 415 | return false; |
michael@0 | 416 | |
michael@0 | 417 | XESetCloseDisplay(display, codes->extension, DisplayClosing); |
michael@0 | 418 | // Add a new DisplayInfo. |
michael@0 | 419 | displays->AppendElement(display); |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | nsTArray<ColormapEntry>* entries = |
michael@0 | 423 | &displays->ElementAt(d).mColormapEntries; |
michael@0 | 424 | |
michael@0 | 425 | // Only a small number of formats are expected to be used, so just do a |
michael@0 | 426 | // simple linear search. |
michael@0 | 427 | for (uint32_t i = 0; i < entries->Length(); ++i) { |
michael@0 | 428 | const ColormapEntry& entry = entries->ElementAt(i); |
michael@0 | 429 | // Only the format and screen need to match. (The visual may differ.) |
michael@0 | 430 | // If there is no format (e.g. no RENDER extension) then just compare |
michael@0 | 431 | // the visual. |
michael@0 | 432 | if ((aFormat && entry.mFormat == aFormat && entry.mScreen == aScreen) |
michael@0 | 433 | || aVisual == entry.mVisual) { |
michael@0 | 434 | *aColormap = entry.mColormap; |
michael@0 | 435 | *aVisualForColormap = entry.mVisual; |
michael@0 | 436 | return true; |
michael@0 | 437 | } |
michael@0 | 438 | } |
michael@0 | 439 | |
michael@0 | 440 | // No existing entry. Create a colormap and add an entry. |
michael@0 | 441 | Colormap colormap = XCreateColormap(display, RootWindowOfScreen(aScreen), |
michael@0 | 442 | aVisual, AllocNone); |
michael@0 | 443 | ColormapEntry* newEntry = entries->AppendElement(); |
michael@0 | 444 | newEntry->mFormat = aFormat; |
michael@0 | 445 | newEntry->mScreen = aScreen; |
michael@0 | 446 | newEntry->mVisual = aVisual; |
michael@0 | 447 | newEntry->mColormap = colormap; |
michael@0 | 448 | |
michael@0 | 449 | *aColormap = colormap; |
michael@0 | 450 | *aVisualForColormap = aVisual; |
michael@0 | 451 | return true; |
michael@0 | 452 | } |
michael@0 | 453 | |
michael@0 | 454 | /* static */ int |
michael@0 | 455 | DisplayTable::DisplayClosing(Display *display, XExtCodes* codes) |
michael@0 | 456 | { |
michael@0 | 457 | // No need to free the colormaps explicitly as they will be released when |
michael@0 | 458 | // the connection is closed. |
michael@0 | 459 | sDisplayTable->mDisplays.RemoveElement(display, FindDisplay()); |
michael@0 | 460 | if (sDisplayTable->mDisplays.Length() == 0) { |
michael@0 | 461 | delete sDisplayTable; |
michael@0 | 462 | sDisplayTable = nullptr; |
michael@0 | 463 | } |
michael@0 | 464 | return 0; |
michael@0 | 465 | } |
michael@0 | 466 | |
michael@0 | 467 | /* static */ |
michael@0 | 468 | bool |
michael@0 | 469 | gfxXlibSurface::GetColormapAndVisual(cairo_surface_t* aXlibSurface, |
michael@0 | 470 | Colormap* aColormap, Visual** aVisual) |
michael@0 | 471 | { |
michael@0 | 472 | XRenderPictFormat* format = |
michael@0 | 473 | cairo_xlib_surface_get_xrender_format(aXlibSurface); |
michael@0 | 474 | Screen* screen = cairo_xlib_surface_get_screen(aXlibSurface); |
michael@0 | 475 | Visual* visual = cairo_xlib_surface_get_visual(aXlibSurface); |
michael@0 | 476 | |
michael@0 | 477 | return DisplayTable::GetColormapAndVisual(screen, format, visual, |
michael@0 | 478 | aColormap, aVisual); |
michael@0 | 479 | } |
michael@0 | 480 | |
michael@0 | 481 | bool |
michael@0 | 482 | gfxXlibSurface::GetColormapAndVisual(Colormap* aColormap, Visual** aVisual) |
michael@0 | 483 | { |
michael@0 | 484 | if (!mSurfaceValid) |
michael@0 | 485 | return false; |
michael@0 | 486 | |
michael@0 | 487 | return GetColormapAndVisual(CairoSurface(), aColormap, aVisual); |
michael@0 | 488 | } |
michael@0 | 489 | |
michael@0 | 490 | /* static */ |
michael@0 | 491 | int |
michael@0 | 492 | gfxXlibSurface::DepthOfVisual(const Screen* screen, const Visual* visual) |
michael@0 | 493 | { |
michael@0 | 494 | for (int d = 0; d < screen->ndepths; d++) { |
michael@0 | 495 | const Depth& d_info = screen->depths[d]; |
michael@0 | 496 | if (visual >= &d_info.visuals[0] |
michael@0 | 497 | && visual < &d_info.visuals[d_info.nvisuals]) |
michael@0 | 498 | return d_info.depth; |
michael@0 | 499 | } |
michael@0 | 500 | |
michael@0 | 501 | NS_ERROR("Visual not on Screen."); |
michael@0 | 502 | return 0; |
michael@0 | 503 | } |
michael@0 | 504 | |
michael@0 | 505 | /* static */ |
michael@0 | 506 | Visual* |
michael@0 | 507 | gfxXlibSurface::FindVisual(Screen *screen, gfxImageFormat format) |
michael@0 | 508 | { |
michael@0 | 509 | int depth; |
michael@0 | 510 | unsigned long red_mask, green_mask, blue_mask; |
michael@0 | 511 | switch (format) { |
michael@0 | 512 | case gfxImageFormat::ARGB32: |
michael@0 | 513 | depth = 32; |
michael@0 | 514 | red_mask = 0xff0000; |
michael@0 | 515 | green_mask = 0xff00; |
michael@0 | 516 | blue_mask = 0xff; |
michael@0 | 517 | break; |
michael@0 | 518 | case gfxImageFormat::RGB24: |
michael@0 | 519 | depth = 24; |
michael@0 | 520 | red_mask = 0xff0000; |
michael@0 | 521 | green_mask = 0xff00; |
michael@0 | 522 | blue_mask = 0xff; |
michael@0 | 523 | break; |
michael@0 | 524 | case gfxImageFormat::RGB16_565: |
michael@0 | 525 | depth = 16; |
michael@0 | 526 | red_mask = 0xf800; |
michael@0 | 527 | green_mask = 0x7e0; |
michael@0 | 528 | blue_mask = 0x1f; |
michael@0 | 529 | break; |
michael@0 | 530 | case gfxImageFormat::A8: |
michael@0 | 531 | case gfxImageFormat::A1: |
michael@0 | 532 | default: |
michael@0 | 533 | return nullptr; |
michael@0 | 534 | } |
michael@0 | 535 | |
michael@0 | 536 | for (int d = 0; d < screen->ndepths; d++) { |
michael@0 | 537 | const Depth& d_info = screen->depths[d]; |
michael@0 | 538 | if (d_info.depth != depth) |
michael@0 | 539 | continue; |
michael@0 | 540 | |
michael@0 | 541 | for (int v = 0; v < d_info.nvisuals; v++) { |
michael@0 | 542 | Visual* visual = &d_info.visuals[v]; |
michael@0 | 543 | |
michael@0 | 544 | if (visual->c_class == TrueColor && |
michael@0 | 545 | visual->red_mask == red_mask && |
michael@0 | 546 | visual->green_mask == green_mask && |
michael@0 | 547 | visual->blue_mask == blue_mask) |
michael@0 | 548 | return visual; |
michael@0 | 549 | } |
michael@0 | 550 | } |
michael@0 | 551 | |
michael@0 | 552 | return nullptr; |
michael@0 | 553 | } |
michael@0 | 554 | |
michael@0 | 555 | /* static */ |
michael@0 | 556 | XRenderPictFormat* |
michael@0 | 557 | gfxXlibSurface::FindRenderFormat(Display *dpy, gfxImageFormat format) |
michael@0 | 558 | { |
michael@0 | 559 | switch (format) { |
michael@0 | 560 | case gfxImageFormat::ARGB32: |
michael@0 | 561 | return XRenderFindStandardFormat (dpy, PictStandardARGB32); |
michael@0 | 562 | case gfxImageFormat::RGB24: |
michael@0 | 563 | return XRenderFindStandardFormat (dpy, PictStandardRGB24); |
michael@0 | 564 | case gfxImageFormat::RGB16_565: { |
michael@0 | 565 | // PictStandardRGB16_565 is not standard Xrender format |
michael@0 | 566 | // we should try to find related visual |
michael@0 | 567 | // and find xrender format by visual |
michael@0 | 568 | Visual *visual = FindVisual(DefaultScreenOfDisplay(dpy), format); |
michael@0 | 569 | if (!visual) |
michael@0 | 570 | return nullptr; |
michael@0 | 571 | return XRenderFindVisualFormat(dpy, visual); |
michael@0 | 572 | } |
michael@0 | 573 | case gfxImageFormat::A8: |
michael@0 | 574 | return XRenderFindStandardFormat (dpy, PictStandardA8); |
michael@0 | 575 | case gfxImageFormat::A1: |
michael@0 | 576 | return XRenderFindStandardFormat (dpy, PictStandardA1); |
michael@0 | 577 | default: |
michael@0 | 578 | break; |
michael@0 | 579 | } |
michael@0 | 580 | |
michael@0 | 581 | return nullptr; |
michael@0 | 582 | } |
michael@0 | 583 | |
michael@0 | 584 | Screen* |
michael@0 | 585 | gfxXlibSurface::XScreen() |
michael@0 | 586 | { |
michael@0 | 587 | return cairo_xlib_surface_get_screen(CairoSurface()); |
michael@0 | 588 | } |
michael@0 | 589 | |
michael@0 | 590 | XRenderPictFormat* |
michael@0 | 591 | gfxXlibSurface::XRenderFormat() |
michael@0 | 592 | { |
michael@0 | 593 | return cairo_xlib_surface_get_xrender_format(CairoSurface()); |
michael@0 | 594 | } |
michael@0 | 595 | |
michael@0 | 596 | #if defined(GL_PROVIDER_GLX) |
michael@0 | 597 | GLXPixmap |
michael@0 | 598 | gfxXlibSurface::GetGLXPixmap() |
michael@0 | 599 | { |
michael@0 | 600 | if (!mGLXPixmap) { |
michael@0 | 601 | #ifdef DEBUG |
michael@0 | 602 | // cairo_surface_has_show_text_glyphs is used solely for the |
michael@0 | 603 | // side-effect of setting the error on surface if |
michael@0 | 604 | // cairo_surface_finish() has been called. |
michael@0 | 605 | cairo_surface_has_show_text_glyphs(CairoSurface()); |
michael@0 | 606 | NS_ASSERTION(CairoStatus() != CAIRO_STATUS_SURFACE_FINISHED, |
michael@0 | 607 | "GetGLXPixmap called after surface finished"); |
michael@0 | 608 | #endif |
michael@0 | 609 | mGLXPixmap = gl::sGLXLibrary.CreatePixmap(this); |
michael@0 | 610 | } |
michael@0 | 611 | return mGLXPixmap; |
michael@0 | 612 | } |
michael@0 | 613 | #endif |
michael@0 | 614 | |
michael@0 | 615 | gfxMemoryLocation |
michael@0 | 616 | gfxXlibSurface::GetMemoryLocation() const |
michael@0 | 617 | { |
michael@0 | 618 | return gfxMemoryLocation::OUT_OF_PROCESS; |
michael@0 | 619 | } |