/// <summary>
        /// Create a surface to cache Pdu.
        /// </summary>
        /// <param name="sid">This is used to indicate surface id.</param>
        /// <param name="key">This is used to indicate a key to associate with the bitmap cache entry.</param>
        /// <param name="slot">This is used to indicate the index of the bitmap cache entry in which
        /// the source bitmap data is stored.</param>
        /// <param name="rect">This is used to indicate rectangle that bounds the source bitmap.</param>
        public RDPGFX_SURFACE_TO_CACHE CreateSurfaceToCachePdu(ushort sid, ulong key, ushort slot, RDPGFX_RECT16 rect)
        {
            RDPGFX_SURFACE_TO_CACHE surfaceToCache = new RDPGFX_SURFACE_TO_CACHE(sid, key, slot, rect);

            return(surfaceToCache);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Verify SUT Display
        /// </summary>
        /// <param name="usingRemoteFX">Whether the output image is using RemoteFX codec</param>
        /// <param name="rect">The Rectangle on the image to be compared</param>
        /// <param name="callStackIndex">Call stack index from the test method, which help to get test method name in the function</param>
        private void VerifySUTDisplay(bool usingRemoteFX, RDPGFX_RECT16 rect, int callStackIndex = 1)
        {
            Rectangle compareRect = new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);

            base.VerifySUTDisplay(usingRemoteFX, compareRect, callStackIndex + 1);
        }
Exemplo n.º 3
0
        public void RDPEGFX_SurfaceToSurface_PositiveTest_DestRectsOverlapped()
        {
            uint fid;

            // Init for capability exchange
            RDPEGFX_CapabilityExchange();

            // Create & output source surface, then fill it with green color
            RDPGFX_RECT16 surfRect = RdpegfxTestUtility.ConvertToRect(RdpegfxTestUtility.surfPos, RdpegfxTestUtility.surfWidth, RdpegfxTestUtility.surfHeight);
            Surface       surf     = this.rdpegfxAdapter.CreateAndOutputSurface(surfRect, PixelFormat.PIXEL_FORMAT_ARGB_8888);

            this.TestSite.Assert.IsNotNull(surf, "Surface {0} is created", surf.Id);

            RDPGFX_RECT16 fillSurfRect = RdpegfxTestUtility.ConvertToRect(RdpegfxTestUtility.imgPos, RdpegfxTestUtility.surfWidth, RdpegfxTestUtility.surfHeight);

            RDPGFX_RECT16[] fillRects = { fillSurfRect };  // Relative to surface
            fid = this.rdpegfxAdapter.SolidFillSurface(surf, RdpegfxTestUtility.fillColorGreen, fillRects);
            this.TestSite.Log.Add(LogEntryKind.Debug, "Surface is filled with solid color in frame: {0}", fid);

            this.rdpegfxAdapter.ExpectFrameAck(fid);

            // Create & output destination surface, then fill it with blue color
            RDPGFX_RECT16 surfRect2 = RdpegfxTestUtility.ConvertToRect(RdpegfxTestUtility.surfPos2, RdpegfxTestUtility.surfWidth2, RdpegfxTestUtility.surfHeight2);
            Surface       surf2     = this.rdpegfxAdapter.CreateAndOutputSurface(surfRect2, PixelFormat.PIXEL_FORMAT_ARGB_8888);

            this.TestSite.Assert.IsNotNull(surf, "Surface {0} is created", surf2.Id);

            RDPGFX_RECT16 fillSurfRect2 = RdpegfxTestUtility.ConvertToRect(RdpegfxTestUtility.imgPos, RdpegfxTestUtility.surfWidth2, RdpegfxTestUtility.surfHeight2);

            RDPGFX_RECT16[] fillRects2 = { fillSurfRect2 };
            fid = this.rdpegfxAdapter.SolidFillSurface(surf2, RdpegfxTestUtility.fillColorBlue, fillRects2);
            this.TestSite.Log.Add(LogEntryKind.Debug, "Surface is filled with solid color in frame {0}, dest rects are overlapped each other", fid);
            this.rdpegfxAdapter.ExpectFrameAck(fid);

            // Generate destPts array
            List <RDPGFX_POINT16> destPtsList = new List <RDPGFX_POINT16>();
            // First point
            int x = 0;
            int y = 0;

            destPtsList.Add(new RDPGFX_POINT16((ushort)x, (ushort)y));

            // Second Point, the rect ovelap partial of the first one
            x = RdpegfxTestUtility.copySrcRect.Width / 2;
            y = RdpegfxTestUtility.copySrcRect.Height / 2;
            destPtsList.Add(new RDPGFX_POINT16((ushort)x, (ushort)y));

            fid = this.rdpegfxAdapter.InterSurfaceCopy(surf, RdpegfxTestUtility.copySrcRect, RdpegfxTestUtility.fillColorRed, surf2, destPtsList.ToArray());
            this.TestSite.Log.Add(LogEntryKind.Debug, "Send RDPGFX_SURFACE_TO_SURFACE_PDU message in frame: {0}", fid);

            this.rdpegfxAdapter.ExpectFrameAck(fid);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Verify output on SUT Display if the verifySUTDisplay entry in PTF config is true.");
            this.VerifySUTDisplay(false, new RDPGFX_RECT16[] { surfRect, surfRect2 });

            // Delete the surfaces
            this.rdpegfxAdapter.DeleteSurface(surf.Id);
            this.TestSite.Log.Add(LogEntryKind.Debug, "Surface {0} is deleted", surf.Id);
            this.rdpegfxAdapter.DeleteSurface(surf2.Id);
            this.TestSite.Log.Add(LogEntryKind.Debug, "Surface {0} is deleted", surf2.Id);
        }
        /// <summary>
        /// Create a wire to surface Pdu1.
        /// </summary>
        /// <param name="sId">This is used to indicate the target surface id.</param>
        /// <param name="cId">This is used to indicate the codecId.</param>
        /// <param name="pixFormat">This is used to indicate the pixel format to fill target surface.</param>
        /// <param name="bmRect">This is used to indicate border of bitmap on target surface.</param>
        /// <param name="bmLen">This is used to indicate the length of bitmap data.</param>
        /// <param name="bmData">This is used to indicate the bitmap data encoded by cId codec.</param>
        public RDPGFX_WIRE_TO_SURFACE_PDU_1 CreateWireToSurfacePdu1(ushort sId, CodecType cId, PixelFormat pixFormat, RDPGFX_RECT16 bmRect, byte[] bmData)
        {
            RDPGFX_WIRE_TO_SURFACE_PDU_1 wireToSurf1 = new RDPGFX_WIRE_TO_SURFACE_PDU_1(sId, cId, pixFormat, bmRect, bmData);

            return(wireToSurf1);
        }
        public void RDPEGFX_WireToSurface_PositiveTest_ImageBorderOverlapSurface()
        {
            this.TestSite.Log.Add(LogEntryKind.Comment, "Do capability exchange.");
            // Init for capability exchange
            RDPEGFX_CapabilityExchange();

            this.TestSite.Log.Add(LogEntryKind.Comment, "Create a surface and fill it with green color.");
            // Create & output a surface
            RDPGFX_RECT16 surfRect = RdpegfxTestUtility.ConvertToRect(RdpegfxTestUtility.surfPos, RdpegfxTestUtility.surfWidth, RdpegfxTestUtility.surfHeight);
            Surface       surf     = this.rdpegfxAdapter.CreateAndOutputSurface(surfRect, PixelFormat.PIXEL_FORMAT_XRGB_8888);

            this.TestSite.Assert.IsNotNull(surf, "Surface {0} is created", surf.Id);

            // Send solid fill request to client to fill surface with green color
            RDPGFX_RECT16 fillSurfRect = RdpegfxTestUtility.ConvertToRect(RdpegfxTestUtility.imgPos, RdpegfxTestUtility.surfWidth, RdpegfxTestUtility.surfHeight);

            RDPGFX_RECT16[] fillRects = { fillSurfRect };  // Relative to surface
            uint            fid       = this.rdpegfxAdapter.SolidFillSurface(surf, RdpegfxTestUtility.fillColorGreen, fillRects);

            this.TestSite.Log.Add(LogEntryKind.Debug, "Surface is filled with solid color in frame: {0}.", fid);
            this.rdpegfxAdapter.ExpectFrameAck(fid);

            Image bgImage;
            Image compImage = RdpegfxTestUtility.captureFromImage(image_64X64, RdpegfxTestUtility.imgPos,
                                                                  RdpegfxTestUtility.smallWidth, RdpegfxTestUtility.smallHeight, out bgImage);
            byte compFlag = (byte)PACKET_COMPR_FLAG.PACKET_COMPR_TYPE_RDP8;

            // Top-right corner
            this.TestSite.Log.Add(LogEntryKind.Comment, "The bitmap is sent to the client by frame {0}. whose top and right borders are overlapped with surface.", fid);
            int y = 0;
            int x = RdpegfxTestUtility.surfWidth - RdpegfxTestUtility.smallWidth;

            fid = this.rdpegfxAdapter.SendUncompressedImage(compImage, (ushort)x, (ushort)y, surf.Id, PixelFormat.PIXEL_FORMAT_XRGB_8888, compFlag, RdpegfxTestUtility.segmentPartSize);
            this.rdpegfxAdapter.ExpectFrameAck(fid);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Verify output on SUT Display if the verifySUTDisplay entry in PTF config is true.");
            this.VerifySUTDisplay(false, surfRect);

            // Bottom-right corner
            this.TestSite.Log.Add(LogEntryKind.Comment, "The bitmap is sent to the client by frame {0}. whose bottom and right borders are overlapped with surface", fid);
            y   = RdpegfxTestUtility.surfHeight - RdpegfxTestUtility.smallHeight;
            x   = RdpegfxTestUtility.surfWidth - RdpegfxTestUtility.smallWidth;
            fid = this.rdpegfxAdapter.SendUncompressedImage(compImage, (ushort)x, (ushort)y, surf.Id, PixelFormat.PIXEL_FORMAT_XRGB_8888, compFlag, RdpegfxTestUtility.segmentPartSize);
            this.rdpegfxAdapter.ExpectFrameAck(fid);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Verify output on SUT Display if the verifySUTDisplay entry in PTF config is true.");
            this.VerifySUTDisplay(false, surfRect);

            // Bottom-left corner
            this.TestSite.Log.Add(LogEntryKind.Comment, "The bitmap is sent to the client by frame {0}. whose bottom and left borders are overlapped with surface", fid);
            y   = RdpegfxTestUtility.surfHeight - RdpegfxTestUtility.smallHeight;
            x   = 0;
            fid = this.rdpegfxAdapter.SendUncompressedImage(compImage, (ushort)x, (ushort)y, surf.Id, PixelFormat.PIXEL_FORMAT_XRGB_8888, compFlag, RdpegfxTestUtility.segmentPartSize);
            this.rdpegfxAdapter.ExpectFrameAck(fid);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Verify output on SUT Display if the verifySUTDisplay entry in PTF config is true.");
            this.VerifySUTDisplay(false, surfRect);

            // Delete the surface
            this.rdpegfxAdapter.DeleteSurface(surf.Id);
            this.TestSite.Log.Add(LogEntryKind.Debug, "Surface {0} is deleted", surf.Id);
        }
        /// <summary>
        /// Create a surface to surface Pdu.
        /// </summary>
        /// <param name="srcSID">This is used to indicate source surface id.</param>
        /// <param name="destSID">This is used to indicate destination surface id.</param>
        /// <param name="srcRect">This is used to indicate source rectangle bitmap area to be copied.</param>
        /// <param name="destPoints">This is used to specify destination points of source rectangle bitmap to be copied. </param>
        public RDPGFX_SURFACE_TO_SURFACE CreateSurfaceToSurfacePdu(ushort srcSID, ushort destSID, RDPGFX_RECT16 srcRect, RDPGFX_POINT16[] destPoints)
        {
            RDPGFX_SURFACE_TO_SURFACE surfToSurf = new RDPGFX_SURFACE_TO_SURFACE(srcSID, destSID, srcRect);

            if (destPoints != null)
            {
                for (int i = 0; i < destPoints.Length; i++)
                {
                    surfToSurf.AddDestPosition(destPoints[i]);
                }
            }
            return(surfToSurf);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Common function to send H264 data to the client
        /// </summary>
        /// <param name="h264DataFile">XML file of H264 data</param>
        /// <param name="isAVC444">Whether need RDP client support AVC444/AVC444v2</param>
        private void SendH264CodecStream(string h264DataFile, bool isAVC444)
        {
            //Load H264 data
            RdpegfxH264TestDatas h264TestData = GetH264TestData(h264DataFile);

            // Init for capability exchange
            this.TestSite.Log.Add(LogEntryKind.Comment, "Do capability exchange.");
            RDPEGFX_CapabilityExchange();
            if (isAVC444)
            {
                this.TestSite.Assume.IsTrue(this.isH264AVC444Supported, "This test case requires RDP client to support AVC444/AVC444v2.");
            }
            else
            {
                this.TestSite.Assume.IsTrue(this.isH264AVC420Supported, "To test H264 codec, client must indicate support for H264 codec in RDPGFX_CAPS_ADVERTISE_PDU");
            }

            this.TestSite.Log.Add(LogEntryKind.Comment, "Create a surface and fill it with green color.");
            // Create & output a surface
            RDPGFX_POINT16 surfPos     = new RDPGFX_POINT16((ushort)h264TestData.SurfaceInfo.outputOriginX, (ushort)h264TestData.SurfaceInfo.outputOriginY);
            RDPGFX_RECT16  surfRect    = RdpegfxTestUtility.ConvertToRect(surfPos, h264TestData.SurfaceInfo.width, h264TestData.SurfaceInfo.height);
            RDPGFX_RECT16  compareRect = RdpegfxTestUtility.ConvertToRect(surfPos, h264TestData.SurfaceInfo.width, h264TestData.SurfaceInfo.height);

            if (isWindowsImplementation && compareRect.top < 32 && compareRect.bottom > 32)
            {
                // Ignore the field of RDP client connection bar
                compareRect.top = 32;
            }
            Surface surf = this.rdpegfxAdapter.CreateAndOutputSurface(surfRect, (PixelFormat)h264TestData.SurfaceInfo.pixelFormat);

            this.TestSite.Assert.IsNotNull(surf, "Surface {0} is created", surf.Id);

            // Send solid fill request to client to fill surface with green color
            RDPGFX_RECT16[] fillRects = { new RDPGFX_RECT16(h264TestData.TestDataList[0].DestRect.left,
                                                            h264TestData.TestDataList[0].DestRect.top,
                                                            h264TestData.TestDataList[0].DestRect.right,
                                                            h264TestData.TestDataList[0].DestRect.bottom) }; // Relative to surface
            uint            fid = this.rdpegfxAdapter.SolidFillSurface(surf, RdpegfxTestUtility.fillColorGreen, fillRects);

            this.TestSite.Log.Add(LogEntryKind.Debug, "Surface is filled with solid color in frame: {0}", fid);
            this.rdpegfxAdapter.ExpectFrameAck(fid);

            // Send H264 codec data
            foreach (TestData data in h264TestData.TestDataList)
            {
                ushort        codecId   = data.codecId;
                PixelFormat   pixFormat = (PixelFormat)data.pixelFormat;
                RDPGFX_RECT16 bmRect    = new RDPGFX_RECT16();
                bmRect.left   = data.DestRect.left;
                bmRect.top    = data.DestRect.top;
                bmRect.right  = data.DestRect.right;
                bmRect.bottom = data.DestRect.bottom;

                if (codecId == (ushort)CodecType.RDPGFX_CODECID_AVC420 && data.AVC420BitmapStream != null)
                {
                    this.TestSite.Log.Add(LogEntryKind.Comment, "Sending H264 AVC420 Encoded Bitmap Data Messages to client.");
                    fid = this.rdpegfxAdapter.SendImageWithH264AVC420Codec(surf.Id, pixFormat, bmRect, data.AVC420BitmapStream.To_RFX_AVC420_BITMAP_STREAM(), data.GetBaseImage());
                    // Test case pass if frame acknowledge is received.
                    this.rdpegfxAdapter.ExpectFrameAck(fid);
                }
                else if (codecId == (ushort)CodecType.RDPGFX_CODECID_AVC444 && data.AVC444BitmapStream != null)
                {
                    this.TestSite.Log.Add(LogEntryKind.Comment, "Sending H264 AVC444 Encoded Bitmap Data Messages to client.");
                    fid = this.rdpegfxAdapter.SendImageWithH264AVC444Codec(surf.Id, pixFormat, bmRect, CodecType.RDPGFX_CODECID_AVC444, data.AVC444BitmapStream.To_RFX_AVC444_BITMAP_STREAM(), data.GetBaseImage());
                    // Test case pass if frame acknowledge is received.
                    this.rdpegfxAdapter.ExpectFrameAck(fid);
                }
                else if (codecId == (ushort)CodecType.RDPGFX_CODECID_AVC444v2 && data.AVC444v2BitmapStream != null)
                {
                    this.TestSite.Log.Add(LogEntryKind.Comment, "Sending H264 AVC444v2 Encoded Bitmap Data Messages to client.");
                    fid = this.rdpegfxAdapter.SendImageWithH264AVC444Codec(surf.Id, pixFormat, bmRect, CodecType.RDPGFX_CODECID_AVC444v2, data.AVC444v2BitmapStream.To_RFX_AVC444V2_BITMAP_STREAM(), data.GetBaseImage());
                    // Test case pass if frame acknowledge is received.
                    this.rdpegfxAdapter.ExpectFrameAck(fid);
                }
                else
                {
                    Site.Assert.Fail("Test data doesn't contain proper H264 encoded data corresponding to codec ID.");
                }

                this.TestSite.Log.Add(LogEntryKind.Comment, "Verify output on SUT Display if the verifySUTDisplay entry in PTF config is true.");
                this.VerifySUTDisplay(true, compareRect, 2);
            }

            // Delete the surface
            this.rdpegfxAdapter.DeleteSurface(surf.Id);
            this.TestSite.Log.Add(LogEntryKind.Debug, "Surface {0} is deleted", surf.Id);
        }
        public void RDPEGFX_SurfaceToScreen_PositiveTest_MultiSurfaceOverlap()
        {
            uint fid;

            this.TestSite.Log.Add(LogEntryKind.Comment, "Do capability exchange.");
            // Init for capability exchange
            RDPEGFX_CapabilityExchange();

            RDPGFX_RECT16 verifyRect = RdpegfxTestUtility.ConvertToRect(RdpegfxTestUtility.surfPos, RdpegfxTestUtility.surfWidth, RdpegfxTestUtility.surfHeight);

            // Init Data for test
            RDPGFX_POINT16[] positions = new RDPGFX_POINT16[4];
            positions[0] = new RDPGFX_POINT16(RdpegfxTestUtility.surfPos.x, RdpegfxTestUtility.surfPos.y);
            positions[1] = new RDPGFX_POINT16((ushort)(RdpegfxTestUtility.surfPos.x + RdpegfxTestUtility.surfWidth / 2), RdpegfxTestUtility.surfPos.y);
            positions[2] = new RDPGFX_POINT16(RdpegfxTestUtility.surfPos.x, (ushort)(RdpegfxTestUtility.surfPos.y + RdpegfxTestUtility.surfHeight / 2));
            positions[3] = new RDPGFX_POINT16(RdpegfxTestUtility.surfPos.x, RdpegfxTestUtility.surfPos.y);

            ushort[] widths = new ushort[4];
            widths[0] = RdpegfxTestUtility.surfWidth;
            widths[1] = (ushort)(RdpegfxTestUtility.surfWidth / 2);
            widths[2] = RdpegfxTestUtility.surfWidth;
            widths[3] = (ushort)(RdpegfxTestUtility.surfWidth / 2);

            ushort[] heights = new ushort[4];
            heights[0] = (ushort)(RdpegfxTestUtility.surfHeight / 2);
            heights[1] = RdpegfxTestUtility.surfHeight;
            heights[2] = (ushort)(RdpegfxTestUtility.surfHeight / 2);
            heights[3] = RdpegfxTestUtility.surfHeight;

            Color[] colors = new Color[4];
            colors[0] = Color.Green;
            colors[1] = Color.Blue;
            colors[2] = Color.Red;
            colors[3] = Color.Yellow;

            Surface[] surfaces = new Surface[4];
            // Test the overlap
            for (int i = 0; i < positions.Length; i++)
            {
                this.TestSite.Log.Add(LogEntryKind.Comment, "Create a surface and fill it with color: {0}.", colors[i]);
                // Create & output a surface
                RDPGFX_RECT16 surfRect = RdpegfxTestUtility.ConvertToRect(positions[i], widths[i], heights[i]);
                surfaces[i] = this.rdpegfxAdapter.CreateAndOutputSurface(surfRect, PixelFormat.PIXEL_FORMAT_XRGB_8888);
                this.TestSite.Assert.IsNotNull(surfaces[i], "Surface {0} is created", surfaces[i].Id);

                // Send solid fill request to client to fill surface with green color
                RDPGFX_RECT16   fillSurfRect = RdpegfxTestUtility.ConvertToRect(RdpegfxTestUtility.imgPos, widths[i], heights[i]);
                RDPGFX_RECT16[] fillRects    = { fillSurfRect }; // Relative to surface
                fid = this.rdpegfxAdapter.SolidFillSurface(surfaces[i], RdpegfxTestUtility.ToRdpgfx_Color32(colors[i]), fillRects);
                this.TestSite.Log.Add(LogEntryKind.Debug, "Surface is filled with solid color in frame: {0}", fid);

                // Expect the client to send a frame acknowledge pdu
                // If the server receives the message, it indicates that the client has been successfully decoded the logical frame of graphics commands
                this.rdpegfxAdapter.ExpectFrameAck(fid);

                this.TestSite.Log.Add(LogEntryKind.Comment, "Verify output on SUT Display if the verifySUTDisplay entry in PTF config is true.");
                this.VerifySUTDisplay(false, verifyRect);
            }
            // Delete the surface
            for (int i = 0; i < surfaces.Length; i++)
            {
                if (surfaces[i] != null)
                {
                    this.rdpegfxAdapter.DeleteSurface(surfaces[i].Id);
                    this.TestSite.Log.Add(LogEntryKind.Debug, "Surface {0} is deleted", surfaces[i].Id);
                }
            }
        }
 /// <summary>
 /// Copy bitmap data from a source surface to the bitmap cache
 /// </summary>
 /// <param name="surfaceId"></param>
 /// <param name="cacheKey"></param>
 /// <param name="cacheSlot"></param>
 /// <param name="rectSrc"></param>
 public void SurfaceToCache(ushort surfaceId, ulong cacheKey, ushort cacheSlot, RDPGFX_RECT16 rectSrc)
 {
     if (surfaceDic.ContainsKey(surfaceId))
     {
         Surface   sur       = surfaceDic[surfaceId];
         CacheItem cacheItem = new CacheItem(cacheKey, cacheSlot, sur.Image, rectSrc);
         bitmapCache[cacheSlot] = cacheItem;
     }
 }
        /// <summary>
        /// Render Clear codec image
        /// </summary>
        /// <param name="surfaceId"></param>
        /// <param name="pixFormat"></param>
        /// <param name="ccFlag"></param>
        /// <param name="graphIdx"></param>
        /// <param name="bmRect"></param>
        /// <param name="residualBmp"></param>
        /// <param name="bands"></param>
        /// <param name="subcodecs"></param>
        public void RenderClearCodecImage(ushort surfaceId, PixelFormat pixFormat, byte ccFlag, ushort graphIdx, RDPGFX_RECT16 bmRect, Image residualBmp,
                                          Dictionary <RDPGFX_POINT16, Bitmap> bands, Dictionary <RDPGFX_POINT16, BMP_INFO> subcodecs)
        {
            Image    paint  = new Bitmap(bmRect.right - bmRect.left, bmRect.bottom - bmRect.top);
            Graphics paintG = Graphics.FromImage(paint);

            if (ccFlag != 0 && ((ccFlag & ClearCodec_BitmapStream.CLEARCODEC_FLAG_GLYPH_INDEX) != 0) &&
                ((ccFlag & ClearCodec_BitmapStream.CLEARCODEC_FLAG_GLYPH_HIT) != 0) &&
                this.clearCodecGlyphStorage.ContainsKey(graphIdx))
            {
                Image     srcImage = this.clearCodecGlyphStorage[graphIdx];
                Rectangle srcRect  = new Rectangle(0, 0, srcImage.Width, srcImage.Height);
                Rectangle destRect = new Rectangle(0, 0, bmRect.right - bmRect.left, bmRect.bottom - bmRect.top);
                paintG.DrawImage(srcImage, destRect, srcRect, GraphicsUnit.Pixel);
            }
            else
            {
                // Draw the first layer: residualData
                if (residualBmp != null && residualBmp.Width <= paint.Width && residualBmp.Height <= residualBmp.Height)
                {
                    paintG.DrawImage(residualBmp, 0, 0);
                }

                // Draw the second layer: bandsData
                if (bands != null)
                {
                    foreach (RDPGFX_POINT16 pos in bands.Keys)
                    {
                        Bitmap image = bands[pos];
                        if (pos.x + image.Width <= paint.Width && pos.y + image.Height <= paint.Height)
                        {
                            paintG.DrawImage(image, pos.x, pos.y);
                        }
                    }
                }

                // Draw the third layer: subcodecData
                if (subcodecs != null)
                {
                    foreach (RDPGFX_POINT16 pos in subcodecs.Keys)
                    {
                        Bitmap image = subcodecs[pos].bmp;
                        if (pos.x + image.Width <= paint.Width && pos.y + image.Height <= paint.Height)
                        {
                            paintG.DrawImage(image, pos.x, pos.y);
                        }
                    }
                }

                paintG.Dispose();
            }

            // Draw the image to the surface
            if (this.surfaceDic.ContainsKey(surfaceId))
            {
                Surface sur = surfaceDic[surfaceId];
                sur.DrawImage(paint, bmRect.left, bmRect.top);
            }

            // Save the image to Glyph Storage
            if (ccFlag != 0 && ((ccFlag & ClearCodec_BitmapStream.CLEARCODEC_FLAG_GLYPH_INDEX) != 0) &&
                ((ccFlag & ClearCodec_BitmapStream.CLEARCODEC_FLAG_GLYPH_HIT) == 0))
            {
                if (this.clearCodecGlyphStorage.ContainsKey(graphIdx))
                {
                    this.clearCodecGlyphStorage.Remove(graphIdx);
                }
                this.clearCodecGlyphStorage.Add(graphIdx, paint);
            }
        }