DrawTarget* ContentClientIncremental::BorrowDrawTargetForPainting(const PaintState& aPaintState, RotatedContentBuffer::DrawIterator* aIter) { if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) { return nullptr; } if (aIter) { if (aIter->mCount++ > 0) { return nullptr; } aIter->mDrawRegion = aPaintState.mRegionToDraw; } DrawTarget* result = nullptr; nsIntRect drawBounds = aPaintState.mRegionToDraw.GetBounds(); MOZ_ASSERT(!mLoanedDrawTarget); // BeginUpdate is allowed to modify the given region, // if it wants more to be repainted than we request. if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { nsIntRegion drawRegionCopy = aPaintState.mRegionToDraw; RefPtr<DrawTarget> onBlack = GetUpdateSurface(BUFFER_BLACK, drawRegionCopy); RefPtr<DrawTarget> onWhite = GetUpdateSurface(BUFFER_WHITE, aPaintState.mRegionToDraw); if (onBlack && onWhite) { NS_ASSERTION(aPaintState.mRegionToDraw == drawRegionCopy, "BeginUpdate should always modify the draw region in the same way!"); FillSurface(onBlack, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(0.0, 0.0, 0.0, 1.0)); FillSurface(onWhite, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(1.0, 1.0, 1.0, 1.0)); mLoanedDrawTarget = Factory::CreateDualDrawTarget(onBlack, onWhite); } else { mLoanedDrawTarget = nullptr; } } else { mLoanedDrawTarget = GetUpdateSurface(BUFFER_BLACK, aPaintState.mRegionToDraw); } if (!mLoanedDrawTarget) { NS_WARNING("unable to get context for update"); return nullptr; } result = mLoanedDrawTarget; mLoanedTransform = mLoanedDrawTarget->GetTransform(); mLoanedTransform.Translate(-drawBounds.x, -drawBounds.y); result->SetTransform(mLoanedTransform); mLoanedTransform.Translate(drawBounds.x, drawBounds.y); if (mContentType == gfxContentType::COLOR_ALPHA) { gfxUtils::ClipToRegion(result, aPaintState.mRegionToDraw); nsIntRect bounds = aPaintState.mRegionToDraw.GetBounds(); result->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height)); } return result; }
CBenchmark() { for (dword i = 0; i < 4; i++) m_PerfData[i] = 0; m_SurfID = CreateSurface(300, 200, 256, 256 + 16); FillSurface(m_SurfID, 0xFFFFFFFF); DrawFrameRect(m_SurfID, 0, 0, 256, 256 + 16, 0xFF808080); ShowSurface(m_SurfID); KeEnableNotification(Nf_VirtualKey); KeEnableNotification(NfKe_TerminateProcess); double T = 0.0; dword FPS = 0; dword T1 = KeGetTime(); for (;;) { for (dword i = 0; i < 6; i++) DrawIter(T - 4.0 * (5 - i), 0xFFFFFFFF); T += 1.0; for (dword i = 0; i < 6; i++) DrawIter(T - 4.0 * (5 - i), 0x004070FF | (((i + 1) * 0x10) << 24)); WaitRedraw(); FPS++; dword T2 = KeGetTime(); if (T2 - T1 >= 1000) { dword AvgFPS = AddPerfData(FPS); T1 = T2; FPS = 0; ShowStat(AvgFPS); } CNotification<4> Nf; dword NfCount = KeGetNotificationCount(); for (dword i = 0; i < NfCount; i++) { Nf.Recv(); if (Nf.GetID() == Nf_VirtualKey) { if (Nf.GetByte(0) == VK_Esc) return; } else if (Nf.GetID() == NfKe_TerminateProcess) return; } } }
/////////////////// // Precalculate a font's colour void CFont::PreCalculate(const SmartPointer<SDL_Surface> & bmpSurf, Color colour) { Uint32 pixel; int x, y; FillSurface(bmpSurf.get(), SDL_MapRGBA(bmpSurf.get()->format, 255, 0, 255, 0)); // Lock the surfaces LOCK_OR_QUIT(bmpSurf); LOCK_OR_QUIT(bmpFont); Uint8 R, G, B, A; const Uint8 sr = colour.r, sg = colour.g, sb = colour.b; // Outline font: replace white pixels with appropriate color, put black pixels if (OutlineFont) { for (y = 0; y < bmpSurf.get()->h; y++) { for (x = 0; x < bmpSurf.get()->w; x++) { pixel = GetPixel(bmpFont.get(), x, y); GetColour4(pixel, bmpFont.get()->format, &R, &G, &B, &A); if (R == 255 && G == 255 && B == 255) // White PutPixel(bmpSurf.get(), x, y, SDL_MapRGBA(bmpSurf.get()->format, sr, sg, sb, A)); else if (!R && !G && !B) // Black PutPixel(bmpSurf.get(), x, y, SDL_MapRGBA(bmpSurf.get()->format, 0, 0, 0, A)); } } // Not outline: replace black pixels with appropriate color } else { for (y = 0; y < bmpSurf.get()->h; y++) { for (x = 0; x < bmpSurf.get()->w; x++) { pixel = GetPixel(bmpFont.get(), x, y); GetColour4(pixel, bmpFont.get()->format, &R, &G, &B, &A); if (!R && !G && !B) // Black PutPixel(bmpSurf.get(), x, y, SDL_MapRGBA(bmpSurf.get()->format, sr, sg, sb, A)); } } } // Unlock the surfaces UnlockSurface(bmpSurf); UnlockSurface(bmpFont); }
ALLEGRO_BITMAP *create_bitmap_ex(int color_depth, int width, int height) { SmartPointer<SDL_Surface> surf; if(color_depth == 8) surf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0,0,0,0); else surf = create_32bpp_sdlsurface__allegroformat(width, height); if(!surf.get()) { errors << "create_bitmap_ex: cannot create surface with " << width << "x" << height << "x" << color_depth << endl; return NULL; } FillSurface(surf.get(), Color()); if(surf->format->BitsPerPixel != color_depth) warnings << "create_bitmap_ex: couldn't create surface with " << color_depth << " bpp" << endl; return create_bitmap_from_sdl(surf); }
// // CDDrawObject::UpdateAndFlipSurfaces(): Prepares the back buffer and flips. // HRESULT CDDrawObject::UpdateAndFlipSurfaces(void) { DbgLog((LOG_TRACE, 5, TEXT("CDDrawObject::UpdateAndFlipSurfaces() entered"))) ; // Draw screen and color key on the current back buffer HRESULT hr = FillSurface(m_pBackBuff) ; if (FAILED(hr)) { DbgLog((LOG_ERROR, 1, TEXT("UpdateAndFlipSurfaces() skipped as FillSurface() failed"), hr)) ; return hr ; // or return S_OK?? } IncCount() ; // increment flip count first m_bFrontBuff = !m_bFrontBuff ; // toggle flag DrawOnSurface(m_pBackBuff) ; // draw next text on the back buffer // Keep trying to flip the buffers until successful while (1) { hr = m_pPrimary->Flip(NULL, 0) ; // flip the surfaces if (DD_OK == hr) // success!! { break ; } if (DDERR_SURFACELOST == hr) // surface lost; try to restore { DbgLog((LOG_TRACE, 5, TEXT("DirectDraw surface was lost. Trying to restore..."))) ; hr = m_pPrimary->Restore() ; if (DD_OK != hr) // couldn't restore surface { DbgLog((LOG_ERROR, 0, TEXT("IDirectDrawSurface::Restore() failed (Error 0x%lx)"), hr)) ; break ; } } if (DDERR_WASSTILLDRAWING != hr) // some weird error -- bail out { DbgLog((LOG_ERROR, 0, TEXT("IDirectDrawSurface::Flip() failed (Error 0x%lx)"), hr)) ; break ; } } return hr ; }
char LoadFont(const char *file) { char fullPath[strlen(DATA_PATH) + strlen(FONT_PATH) + strlen(file) + 1]; sprintf(fullPath, "%s%s%s", DATA_PATH, FONT_PATH, file); #ifdef DEBUG printf("Font path = %s\n", fullPath); #endif // The surface holding the big long list of characters SDL_Surface *fontSurf = FillSurface(fullPath, 0); if (fontSurf == NULL) { return 1; } // For holding the rgb values for pre-rendering differently-colored // letters SDL_Color palette[256]; uint r, g, b; // For finding the left and right side of each character (to determine // width) int leftSide; int rightSide; uint i = 0; uint transColor = SDL_MapRGB(fontSurf->format, 0xff, 0x00, 0xff); int sourceOffset = 0; for (int y = 0; y < fontSurf->h; y += FONT_H) { // Lock the surface (for subsequent GetPixel calls) SDL_LockSurface(fontSurf); /*** Determine the letter's width ***/ // Find left side leftSide = -1; for (int x2 = 0; x2 < FONT_W; x2++) { for (int y2 = y; y2 < y + FONT_H; y2++) { if (GetPixel(fontSurf, x2, y2) != transColor) { leftSide = x2; break; } } if (leftSide != -1) break; } // Find right side rightSide = -1; for (int x2 = FONT_W - 1; x2 > 0; x2--) { for (int y2 = y; y2 < y + FONT_H; y2++) { if (GetPixel(fontSurf, x2, y2) != transColor) { rightSide = x2; break; } } if (rightSide != -1) break; } font[i].w = (rightSide - leftSide) + 1; SDL_UnlockSurface(fontSurf); // Blit this character and pre-render different color versions // of it for (uint j = 0; j < NUM_FONT_COLORS; j++) { // Prepare a surface for this color of the character font[i].surf[j] = MakeSurface(FONT_W, FONT_H); // Blit the temporary fontSurf onto this letter's // surface ApplySurface(-leftSide, sourceOffset, fontSurf, font[i].surf[j]); // Get the rgb values for this color switch (j) { case 0: // Shadow r = 0; g = 0; b = 0; break; case 1: // Normal text r = 220; g = 220; b = 220; break; case 2: // Highlighted text r = 251; g = 177; b = 17; break; case 3: // Title r = 255; g = 255; b = 255; } // Set the palette of the surface for (uint k = 0; k < 256; k++) { palette[k].r = static_cast<Uint8>(r); palette[k].g = static_cast<Uint8>(g); palette[k].b = static_cast<Uint8>(b); } // Change the palette of the surface SDL_SetPalette(font[i].surf[j], SDL_LOGPAL, palette, 0, 256); } i++; if (i > FONT_ARRAY_SIZE - 1) break; sourceOffset -= FONT_H; // Move the big tall bmp up } SDL_FreeSurface(fontSurf); return 0; }
/////////////////// // Set the video mode bool SetVideoMode() { if(bDedicated) { notes << "SetVideoMode: dedicated mode, ignoring" << endl; return true; // ignore this case } if (!tLXOptions) { warnings << "SetVideoMode: Don't know what video mode to set, ignoring" << endl; return false; } bool resetting = false; // Check if already running if (VideoPostProcessor::videoSurface()) { resetting = true; notes << "resetting video mode" << endl; // seems to be a win-only problem, it works without problems here under MacOSX #ifdef WIN32 // using hw surfaces? if ((VideoPostProcessor::videoSurface()->flags & SDL_HWSURFACE) != 0) { warnings << "cannot change video mode because current mode uses hardware surfaces" << endl; // TODO: you would have to reset whole game, this is not enough! // The problem is in all allocated surfaces - they are hardware and when you switch // to window, you will most probably get software rendering // Also, hardware surfaces are freed from the video memory when reseting video mode // so you would first have to convert all surfaces to software and then perform this // TODO: in menu_options, restart the game also for fullscreen-change if hw surfaces are currently used return false; } #endif } else { notes << "setting video mode" << endl; } // uninit first to ensure that the video thread is not running VideoPostProcessor::uninit(); bool HardwareAcceleration = false; int DoubleBuf = false; int vidflags = 0; // it is faster with doublebuffering in hardware accelerated mode // also, it seems that it's possible that there are effects in hardware mode with double buf disabled // Use doublebuf when hardware accelerated if (HardwareAcceleration) DoubleBuf = true; // Check that the bpp is valid switch (tLXOptions->iColourDepth) { case 0: case 16: case 24: case 32: break; default: tLXOptions->iColourDepth = 16; } notes << "ColorDepth: " << tLXOptions->iColourDepth << endl; // BlueBeret's addition (2007): OpenGL support bool opengl = tLXOptions->bOpenGL; // Initialize the video if(tLXOptions->bFullscreen) { vidflags |= SDL_FULLSCREEN; } if (opengl) { vidflags |= SDL_OPENGL; #ifndef REAL_OPENGL vidflags |= SDL_OPENGLBLIT; // SDL will behave like normally #endif // HINT: it seems that with OGL activated, SDL_SetVideoMode will already set the OGL depth size // though this main pixel format of the screen surface was always 32 bit for me in OGL under MacOSX //#ifndef MACOSX /* short colorbitsize = (tLXOptions->iColourDepth==16) ? 5 : 8; SDL_GL_SetAttribute (SDL_GL_RED_SIZE, colorbitsize); SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, colorbitsize); SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, colorbitsize); SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, colorbitsize); //SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, tLXOptions->iColourDepth); */ //#endif //SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8); //SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24); //SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 32); SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); // always use double buffering in OGL mode } if(HardwareAcceleration) { vidflags |= SDL_HWSURFACE | SDL_HWPALETTE | SDL_HWACCEL; // Most (perhaps all) systems use software drawing for their stuff (windows etc.) // Because of that we cannot have hardware accelerated support in window - OS screen // is software surface. How would you make the window hardware, if it's on the screen? // Anyway, SDL takes care of this by istelf and disables the flag when needed iSurfaceFormat = SDL_HWSURFACE; } else { vidflags |= SDL_SWSURFACE; iSurfaceFormat = SDL_SWSURFACE; } if(DoubleBuf && !opengl) vidflags |= SDL_DOUBLEBUF; #ifdef WIN32 UnSubclassWindow(); // Unsubclass before doing anything with the window #endif #ifdef WIN32 // Reset the video subsystem under WIN32, else we get a "Could not reset OpenGL context" error when switching mode if (opengl && tLX) { // Don't reset when we're setting up the mode for first time (OpenLieroX not yet initialized) SDL_QuitSubSystem(SDL_INIT_VIDEO); SDL_InitSubSystem(SDL_INIT_VIDEO); } #endif VideoPostProcessor::init(); int scrW = VideoPostProcessor::get()->screenWidth(); int scrH = VideoPostProcessor::get()->screenHeight(); setvideomode: if( SDL_SetVideoMode(scrW, scrH, tLXOptions->iColourDepth, vidflags) == NULL) { if (resetting) { errors << "Failed to reset video mode" << " (ErrorMsg: " << SDL_GetError() << ")," << " let's wait a bit and retry" << endl; SDL_Delay(500); resetting = false; goto setvideomode; } if(tLXOptions->iColourDepth != 0) { errors << "Failed to use " << tLXOptions->iColourDepth << " bpp" << " (ErrorMsg: " << SDL_GetError() << ")," << " trying automatic bpp detection ..." << endl; tLXOptions->iColourDepth = 0; goto setvideomode; } if(vidflags & SDL_OPENGL) { errors << "Failed to use OpenGL" << " (ErrorMsg: " << SDL_GetError() << ")," << " trying without ..." << endl; vidflags &= ~(SDL_OPENGL | SDL_OPENGLBLIT | SDL_HWSURFACE | SDL_HWPALETTE | SDL_HWACCEL); goto setvideomode; } if(vidflags & SDL_FULLSCREEN) { errors << "Failed to set full screen video mode " << scrW << "x" << scrH << "x" << tLXOptions->iColourDepth << " (ErrorMsg: " << SDL_GetError() << ")," << " trying window mode ..." << endl; vidflags &= ~SDL_FULLSCREEN; goto setvideomode; } SystemError("Failed to set the video mode " + itoa(scrW) + "x" + itoa(scrH) + "x" + itoa(tLXOptions->iColourDepth) + "\nErrorMsg: " + std::string(SDL_GetError())); return false; } SDL_WM_SetCaption(GetGameVersion().asHumanString().c_str(),NULL); SDL_ShowCursor(SDL_DISABLE); #ifdef WIN32 // Hint: Reset the mouse state - this should avoid the mouse staying pressed GetMouse()->Button = 0; GetMouse()->Down = 0; GetMouse()->FirstDown = 0; GetMouse()->Up = 0; if (!tLXOptions->bFullscreen) { SubclassWindow(); } #endif // Set the change mode flag if (tLX) tLX->bVideoModeChanged = true; #ifdef REAL_OPENGL if((SDL_GetVideoSurface()->flags & SDL_OPENGL)) { static SDL_PixelFormat OGL_format32 = { NULL, //SDL_Palette *palette; 32, //Uint8 BitsPerPixel; 4, //Uint8 BytesPerPixel; 0, 0, 0, 0, //Uint8 Rloss, Gloss, Bloss, Aloss; #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */ 0, 8, 16, 24, //Uint8 Rshift, Gshift, Bshift, Ashift; 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000, #else 24, 16, 8, 0, //Uint8 Rshift, Gshift, Bshift, Ashift; 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF, #endif 0, //Uint32 colorkey; 255 //Uint8 alpha; }; // some GFX stuff in OLX seems very slow when this is used // (probably the blit from alpha surf to this format is slow) /* static SDL_PixelFormat OGL_format24 = { NULL, //SDL_Palette *palette; 24, //Uint8 BitsPerPixel; 3, //Uint8 BytesPerPixel; 0, 0, 0, 0, //Uint8 Rloss, Gloss, Bloss, Aloss; #if SDL_BYTEORDER == SDL_LIL_ENDIAN // OpenGL RGBA masks 0, 8, 16, 0, //Uint8 Rshift, Gshift, Bshift, Ashift; 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000, #else 16, 8, 0, 0, //Uint8 Rshift, Gshift, Bshift, Ashift; 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000, #endif 0, //Uint32 colorkey; 255 //Uint8 alpha; }; */ //if(tLXOptions->iColourDepth == 32) mainPixelFormat = &OGL_format32; //else // mainPixelFormat = &OGL_format24; } else #endif mainPixelFormat = SDL_GetVideoSurface()->format; DumpPixelFormat(mainPixelFormat); if(SDL_GetVideoSurface()->flags & SDL_DOUBLEBUF) notes << "using doublebuffering" << endl; // Correct the surface format according to SDL #ifdef REAL_OPENGL if(((SDL_GetVideoSurface()->flags & SDL_OPENGL) != 0)) { iSurfaceFormat = SDL_SWSURFACE; } else #endif if((SDL_GetVideoSurface()->flags & SDL_HWSURFACE) != 0) { iSurfaceFormat = SDL_HWSURFACE; notes << "using hardware surfaces" << endl; } else { iSurfaceFormat = SDL_SWSURFACE; // HINT: under MacOSX, it doesn't seem to make any difference in performance if (HardwareAcceleration) hints << "Unable to use hardware surfaces, falling back to software." << endl; notes << "using software surfaces" << endl; } if(SDL_GetVideoSurface()->flags & SDL_OPENGL) { hints << "using OpenGL" << endl; #ifdef REAL_OPENGL OGL_init(); #else FillSurface(SDL_GetVideoSurface(), Color(0, 0, 0)); #endif } else FillSurface(SDL_GetVideoSurface(), Color(0, 0, 0)); VideoPostProcessor::get()->resetVideo(); notes << "video mode was set successfully" << endl; return true; }
ThebesLayerBuffer::PaintState ContentClientIncremental::BeginPaintBuffer(ThebesLayer* aLayer, ThebesLayerBuffer::ContentType aContentType, uint32_t aFlags) { mTextureInfo.mDeprecatedTextureHostFlags = 0; PaintState result; // We need to disable rotation if we're going to be resampled when // drawing, because we might sample across the rotation boundary. bool canHaveRotation = !(aFlags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE); nsIntRegion validRegion = aLayer->GetValidRegion(); Layer::SurfaceMode mode; ContentType contentType; nsIntRegion neededRegion; bool canReuseBuffer; nsIntRect destBufferRect; while (true) { mode = aLayer->GetSurfaceMode(); contentType = aContentType; neededRegion = aLayer->GetVisibleRegion(); // If we're going to resample, we need a buffer that's in clamp mode. canReuseBuffer = neededRegion.GetBounds().Size() <= mBufferRect.Size() && mHasBuffer && (!(aFlags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE) || !(mTextureInfo.mTextureFlags & TEXTURE_ALLOW_REPEAT)); if (canReuseBuffer) { if (mBufferRect.Contains(neededRegion.GetBounds())) { // We don't need to adjust mBufferRect. destBufferRect = mBufferRect; } else { // The buffer's big enough but doesn't contain everything that's // going to be visible. We'll move it. destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size()); } } else { destBufferRect = neededRegion.GetBounds(); } if (mode == Layer::SURFACE_COMPONENT_ALPHA) { if (!gfxPlatform::ComponentAlphaEnabled() || !aLayer->GetParent() || !aLayer->GetParent()->SupportsComponentAlphaChildren()) { mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; } else { contentType = gfxASurface::CONTENT_COLOR; } } if ((aFlags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE) && (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) || neededRegion.GetNumRects() > 1)) { // The area we add to neededRegion might not be painted opaquely if (mode == Layer::SURFACE_OPAQUE) { contentType = gfxASurface::CONTENT_COLOR_ALPHA; mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; } // For component alpha layers, we leave contentType as CONTENT_COLOR. // We need to validate the entire buffer, to make sure that only valid // pixels are sampled neededRegion = destBufferRect; } if (mHasBuffer && (mContentType != contentType || (mode == Layer::SURFACE_COMPONENT_ALPHA) != mHasBufferOnWhite)) { // We're effectively clearing the valid region, so we need to draw // the entire needed region now. result.mRegionToInvalidate = aLayer->GetValidRegion(); validRegion.SetEmpty(); mHasBuffer = false; mHasBufferOnWhite = false; mBufferRect.SetRect(0, 0, 0, 0); mBufferRotation.MoveTo(0, 0); // Restart decision process with the cleared buffer. We can only go // around the loop one more iteration, since mTexImage is null now. continue; } break; } result.mRegionToDraw.Sub(neededRegion, validRegion); if (result.mRegionToDraw.IsEmpty()) return result; if (destBufferRect.width > mForwarder->GetMaxTextureSize() || destBufferRect.height > mForwarder->GetMaxTextureSize()) { return result; } // BlitTextureImage depends on the FBO texture target being // TEXTURE_2D. This isn't the case on some older X1600-era Radeons. if (!mForwarder->SupportsTextureBlitting() || !mForwarder->SupportsPartialUploads()) { result.mRegionToDraw = neededRegion; validRegion.SetEmpty(); mHasBuffer = false; mHasBufferOnWhite = false; mBufferRect.SetRect(0, 0, 0, 0); mBufferRotation.MoveTo(0, 0); canReuseBuffer = false; } nsIntRect drawBounds = result.mRegionToDraw.GetBounds(); bool createdBuffer = false; uint32_t bufferFlags = canHaveRotation ? TEXTURE_ALLOW_REPEAT : 0; if (mode == Layer::SURFACE_COMPONENT_ALPHA) { bufferFlags |= TEXTURE_COMPONENT_ALPHA; } if (canReuseBuffer) { nsIntRect keepArea; if (keepArea.IntersectRect(destBufferRect, mBufferRect)) { // Set mBufferRotation so that the pixels currently in mBuffer // will still be rendered in the right place when mBufferRect // changes to destBufferRect. nsIntPoint newRotation = mBufferRotation + (destBufferRect.TopLeft() - mBufferRect.TopLeft()); WrapRotationAxis(&newRotation.x, mBufferRect.width); WrapRotationAxis(&newRotation.y, mBufferRect.height); NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation), "newRotation out of bounds"); int32_t xBoundary = destBufferRect.XMost() - newRotation.x; int32_t yBoundary = destBufferRect.YMost() - newRotation.y; if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) || (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) || (newRotation != nsIntPoint(0,0) && !canHaveRotation)) { // The stuff we need to redraw will wrap around an edge of the // buffer, so we will need to do a self-copy // If mBufferRotation == nsIntPoint(0,0) we could do a real // self-copy but we're not going to do that in GL yet. // We can't do a real self-copy because the buffer is rotated. // So allocate a new buffer for the destination. destBufferRect = neededRegion.GetBounds(); createdBuffer = true; } else { mBufferRect = destBufferRect; mBufferRotation = newRotation; } } else { // No pixels are going to be kept. The whole visible region // will be redrawn, so we don't need to copy anything, so we don't // set destBuffer. mBufferRect = destBufferRect; mBufferRotation = nsIntPoint(0,0); } } else { // The buffer's not big enough, so allocate a new one createdBuffer = true; } NS_ASSERTION(!(aFlags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(), "If we're resampling, we need to validate the entire buffer"); if (!createdBuffer && !mHasBuffer) { return result; } if (createdBuffer) { if (mHasBuffer && (mode != Layer::SURFACE_COMPONENT_ALPHA || mHasBufferOnWhite)) { mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_COPY_PREVIOUS; } mHasBuffer = true; if (mode == Layer::SURFACE_COMPONENT_ALPHA) { mHasBufferOnWhite = true; } mBufferRect = destBufferRect; mBufferRotation = nsIntPoint(0,0); NotifyBufferCreated(contentType, bufferFlags); } NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0), "Rotation disabled, but we have nonzero rotation?"); nsIntRegion invalidate; invalidate.Sub(aLayer->GetValidRegion(), destBufferRect); result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate); // BeginUpdate is allowed to modify the given region, // if it wants more to be repainted than we request. if (mode == Layer::SURFACE_COMPONENT_ALPHA) { nsIntRegion drawRegionCopy = result.mRegionToDraw; nsRefPtr<gfxASurface> onBlack = GetUpdateSurface(BUFFER_BLACK, drawRegionCopy); nsRefPtr<gfxASurface> onWhite = GetUpdateSurface(BUFFER_WHITE, result.mRegionToDraw); if (onBlack && onWhite) { NS_ASSERTION(result.mRegionToDraw == drawRegionCopy, "BeginUpdate should always modify the draw region in the same way!"); FillSurface(onBlack, result.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(0.0, 0.0, 0.0, 1.0)); FillSurface(onWhite, result.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(1.0, 1.0, 1.0, 1.0)); if (RefPtr<DrawTarget> onBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForUpdateSurface(onBlack, onBlack->GetSize())) { RefPtr<DrawTarget> onWhiteDT = gfxPlatform::GetPlatform()->CreateDrawTargetForUpdateSurface(onWhite, onWhite->GetSize()); RefPtr<DrawTarget> dt = Factory::CreateDualDrawTarget(onBlackDT, onWhiteDT); result.mContext = new gfxContext(dt); } else { gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() }; nsRefPtr<gfxTeeSurface> surf = new gfxTeeSurface(surfaces, ArrayLength(surfaces)); // XXX If the device offset is set on the individual surfaces instead of on // the tee surface, we render in the wrong place. Why? gfxPoint deviceOffset = onBlack->GetDeviceOffset(); onBlack->SetDeviceOffset(gfxPoint(0, 0)); onWhite->SetDeviceOffset(gfxPoint(0, 0)); surf->SetDeviceOffset(deviceOffset); // Using this surface as a source will likely go horribly wrong, since // only the onBlack surface will really be used, so alpha information will // be incorrect. surf->SetAllowUseAsSource(false); result.mContext = new gfxContext(surf); } } else { result.mContext = nullptr; } } else { nsRefPtr<gfxASurface> surf = GetUpdateSurface(BUFFER_BLACK, result.mRegionToDraw); if (RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForUpdateSurface(surf, surf->GetSize())) { result.mContext = new gfxContext(dt); } else { result.mContext = new gfxContext(surf); } } if (!result.mContext) { NS_WARNING("unable to get context for update"); return result; } result.mContext->Translate(-gfxPoint(drawBounds.x, drawBounds.y)); // If we do partial updates, we have to clip drawing to the regionToDraw. // If we don't clip, background images will be fillrect'd to the region correctly, // while text or lines will paint outside of the regionToDraw. This becomes apparent // with concave regions. Right now the scrollbars invalidate a narrow strip of the bar // although they never cover it. This leads to two draw rects, the narow strip and the actually // newly exposed area. It would be wise to fix this glitch in any way to have simpler // clip and draw regions. gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw); if (mContentType == gfxASurface::CONTENT_COLOR_ALPHA) { result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR); result.mContext->Paint(); result.mContext->SetOperator(gfxContext::OPERATOR_OVER); } return result; }