293 const TSizMarker &sizMarker = iImageInfo->SizMarker(); |
293 const TSizMarker &sizMarker = iImageInfo->SizMarker(); |
294 |
294 |
295 // To get the right output image size, we must compute the size tile by tile. |
295 // To get the right output image size, we must compute the size tile by tile. |
296 // Compute the width of the output image |
296 // Compute the width of the output image |
297 TInt32 tileCompCanvasWidth = 0; |
297 TInt32 tileCompCanvasWidth = 0; |
298 TInt32 numHorTiles = iImageInfo->NumOfHorizTiles(); |
298 TInt32 numHorTiles = iImageInfo->NumOfHorizTilesL(); |
299 TInt32 tileStartCanvas; |
299 TInt32 tileStartCanvas; |
300 TInt32 tileEndCanvas; |
300 TInt32 tileEndCanvas; |
301 TInt32 tileCompStartCanvas; |
301 TInt32 tileCompStartCanvas; |
302 for(TUint16 indexX = 0; indexX < numHorTiles; ++indexX ) |
302 for(TUint16 indexX = 0; indexX < numHorTiles; ++indexX ) |
303 { |
303 { |
304 tileStartCanvas = Max( ( sizMarker.iXTOsiz + indexX * sizMarker.iXTsiz ), sizMarker.iXOsiz ); |
304 tileStartCanvas = Max( ( sizMarker.iXTOsiz + indexX * sizMarker.iXTsiz ), sizMarker.iXOsiz ); |
305 tileEndCanvas = Min( ( sizMarker.iXTOsiz + ( indexX + 1 ) * sizMarker.iXTsiz ), sizMarker.iXsiz ); |
305 tileEndCanvas = Min( ( sizMarker.iXTOsiz + ( indexX + 1 ) * sizMarker.iXTsiz ), sizMarker.iXsiz ); |
306 |
306 |
307 // Add this tile's contribution to the total size |
307 // Add this tile's contribution to the total size |
308 tileCompStartCanvas = TJ2kUtils::Ceil( tileStartCanvas, sizMarker.iXRsiz[0] ); |
308 tileCompStartCanvas = TJ2kUtils::CeilL( tileStartCanvas, sizMarker.iXRsiz[0] ); |
309 tileCompCanvasWidth += TJ2kUtils::Ceil( tileEndCanvas, sizMarker.iXRsiz[0] ) - tileCompStartCanvas; |
309 tileCompCanvasWidth += TJ2kUtils::CeilL( tileEndCanvas, sizMarker.iXRsiz[0] ) - tileCompStartCanvas; |
310 } |
310 } |
311 |
311 |
312 // Compute the height of the output image |
312 // Compute the height of the output image |
313 TInt32 tileCompCanvasHeight = 0; |
313 TInt32 tileCompCanvasHeight = 0; |
314 TInt32 numVerTiles = iImageInfo->NumOfVertTiles(); |
314 TInt32 numVerTiles = iImageInfo->NumOfVertTilesL(); |
315 for(TUint16 indexY = 0; indexY < numVerTiles; ++indexY ) |
315 for(TUint16 indexY = 0; indexY < numVerTiles; ++indexY ) |
316 { |
316 { |
317 tileStartCanvas = Max( ( sizMarker.iYTOsiz + indexY * sizMarker.iYTsiz ), sizMarker.iYOsiz ); |
317 tileStartCanvas = Max( ( sizMarker.iYTOsiz + indexY * sizMarker.iYTsiz ), sizMarker.iYOsiz ); |
318 tileEndCanvas = Min( ( sizMarker.iYTOsiz + ( indexY + 1 ) * sizMarker.iYTsiz ), sizMarker.iYsiz ); |
318 tileEndCanvas = Min( ( sizMarker.iYTOsiz + ( indexY + 1 ) * sizMarker.iYTsiz ), sizMarker.iYsiz ); |
319 |
319 |
320 // Add this tile's contribution to the total size |
320 // Add this tile's contribution to the total size |
321 tileCompStartCanvas = TJ2kUtils::Ceil( tileStartCanvas, sizMarker.iYRsiz[0] ); |
321 tileCompStartCanvas = TJ2kUtils::CeilL( tileStartCanvas, sizMarker.iYRsiz[0] ); |
322 tileCompCanvasHeight += TJ2kUtils::Ceil( tileEndCanvas, sizMarker.iYRsiz[0] ) - tileCompStartCanvas; |
322 tileCompCanvasHeight += TJ2kUtils::CeilL( tileEndCanvas, sizMarker.iYRsiz[0] ) - tileCompStartCanvas; |
323 } |
323 } |
324 |
324 |
325 iFrame->iOverallSizeInPixels = TSize( tileCompCanvasWidth, tileCompCanvasHeight ); |
325 iFrame->iOverallSizeInPixels = TSize( tileCompCanvasWidth, tileCompCanvasHeight ); |
326 |
326 |
327 iFrame->iFrameCoordsInPixels.SetRect( TPoint( 0, 0 ), iFrame->iOverallSizeInPixels ); |
327 iFrame->iFrameCoordsInPixels.SetRect( TPoint( 0, 0 ), iFrame->iOverallSizeInPixels ); |
454 iUseNewTile = ETrue; |
454 iUseNewTile = ETrue; |
455 iReader.iNewDataStart = iFrame->FrameDataOffset(); |
455 iReader.iNewDataStart = iFrame->FrameDataOffset(); |
456 iStyleUsed = EUnknownDecoder; |
456 iStyleUsed = EUnknownDecoder; |
457 |
457 |
458 iProgressBar = EFalse; |
458 iProgressBar = EFalse; |
459 if ( ( iImageInfo->NumOfHorizTiles() == 1 ) && |
459 if ( ( iImageInfo->NumOfHorizTilesL() == 1 ) && |
460 ( iImageInfo->NumOfVertTiles() == 1 ) ) |
460 ( iImageInfo->NumOfVertTilesL() == 1 ) ) |
461 { |
461 { |
462 // To force a return immediately from ProcessFrameL() |
462 // To force a return immediately from ProcessFrameL() |
463 // on first entry to stimulate the occurrance of |
463 // on first entry to stimulate the occurrance of |
464 // the progress bar |
464 // the progress bar |
465 iProgressBar = ETrue; |
465 iProgressBar = ETrue; |
873 if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) ) |
875 if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) ) |
874 { |
876 { |
875 // We must be missing some data in the marker |
877 // We must be missing some data in the marker |
876 User::Leave( KErrCorrupt ); |
878 User::Leave( KErrCorrupt ); |
877 } |
879 } |
878 |
880 if ( codMarker->iScod & 0x01 ) |
|
881 { |
|
882 CleanupStack::Pop(codMarker->iPrecinctSiz); |
|
883 } |
879 if ( !aMain ) |
884 if ( !aMain ) |
880 { |
885 { |
881 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
886 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
882 |
887 |
883 // Append COD to the current tile and decrement the tile length |
888 // Append COD to the current tile and decrement the tile length |
884 tile.AppendCOD( codMarker, markerLength + KMarkerSize ); |
889 tile.AppendCOD( codMarker, markerLength + KMarkerSize ); |
885 CleanupStack::Pop(); |
890 CleanupStack::PopAndDestroy(codMarker); |
886 } |
891 } |
887 |
892 |
888 // Any valid marker may come after COD marker |
893 // Any valid marker may come after COD marker |
889 iFHState = EStateInUnknown; |
894 iFHState = EStateInUnknown; |
890 return EFrameComplete; |
895 return EFrameComplete; |
973 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
980 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
974 |
981 |
975 // Append COC to the current tile and decrement the tile length |
982 // Append COC to the current tile and decrement the tile length |
976 tile.AppendCOCL( cocMarker, markerLength + KMarkerSize ); |
983 tile.AppendCOCL( cocMarker, markerLength + KMarkerSize ); |
977 } |
984 } |
978 CleanupStack::Pop(); |
985 |
|
986 if ( cocMarker->iScoc & 0x01 ) |
|
987 { |
|
988 CleanupStack::Pop(cocMarker->iPrecinctSiz); |
|
989 } |
|
990 CleanupStack::PopAndDestroy(cocMarker); |
979 |
991 |
980 // Any valid marker may come after COC marker |
992 // Any valid marker may come after COC marker |
981 iFHState = EStateInUnknown; |
993 iFHState = EStateInUnknown; |
982 |
994 |
983 return EFrameComplete; |
995 return EFrameComplete; |
1064 qcdMarker->iExponent->Des().Append( (TUint8)( ( *iReader.iPtr++ >> 3 ) & 0x1f ) ); |
1077 qcdMarker->iExponent->Des().Append( (TUint8)( ( *iReader.iPtr++ >> 3 ) & 0x1f ) ); |
1065 --entries; |
1078 --entries; |
1066 } |
1079 } |
1067 } |
1080 } |
1068 } |
1081 } |
|
1082 |
|
1083 CleanupStack::PushL( qcdMarker->iExponent ); |
|
1084 if ((qcdMarker->iSqcd & 0x1f) || (qcdMarker->iSqcd & 0x01)) |
|
1085 { |
|
1086 CleanupStack::PushL( qcdMarker->iMantissa ); |
|
1087 } |
1069 |
1088 |
1070 // Make sure we read all the data |
1089 // Make sure we read all the data |
1071 if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) ) |
1090 if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) ) |
1072 { |
1091 { |
1073 // We must be missing some data in the marker |
1092 // We must be missing some data in the marker |
1074 User::Leave( KErrCorrupt ); |
1093 User::Leave( KErrCorrupt ); |
1075 } |
1094 } |
1076 |
1095 |
|
1096 |
|
1097 if ((qcdMarker->iSqcd & 0x1f) || (qcdMarker->iSqcd & 0x01)) |
|
1098 { |
|
1099 CleanupStack::Pop( qcdMarker->iMantissa ); |
|
1100 } |
|
1101 |
|
1102 CleanupStack::Pop( qcdMarker->iExponent ); |
|
1103 |
1077 if ( !aMain ) |
1104 if ( !aMain ) |
1078 { |
1105 { |
1079 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
1106 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
1080 |
1107 |
1081 // Append QCD to the current tile and decrement the tile length |
1108 // Append QCD to the current tile and decrement the tile length |
1082 tile.AppendQCD( qcdMarker, markerLength + KMarkerSize ); |
1109 tile.AppendQCD( qcdMarker, markerLength + KMarkerSize ); |
1083 CleanupStack::Pop(); |
1110 //CleanupStack::PopAndDestroy(qcdMarker); |
|
1111 CleanupStack::PopAndDestroy(qcdMarker); |
1084 } |
1112 } |
1085 |
1113 |
1086 // Any valid marker may come after QCD marker |
1114 // Any valid marker may come after QCD marker |
1087 iFHState = EStateInUnknown; |
1115 iFHState = EStateInUnknown; |
1088 |
1116 |
1191 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
1226 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
1192 |
1227 |
1193 // Append QCC to the current tile and decrement the tile length |
1228 // Append QCC to the current tile and decrement the tile length |
1194 tile.AppendQCCL( qccMarker, markerLength + KMarkerSize ); |
1229 tile.AppendQCCL( qccMarker, markerLength + KMarkerSize ); |
1195 } |
1230 } |
1196 CleanupStack::Pop(); |
1231 |
|
1232 if( (qccMarker->iSqcc & 0x1f) || (qccMarker->iSqcc & 0x01) ) |
|
1233 { |
|
1234 CleanupStack::Pop( qccMarker->iMantissa ); |
|
1235 } |
|
1236 |
|
1237 CleanupStack::Pop( qccMarker->iExponent ); |
|
1238 CleanupStack::PopAndDestroy(qccMarker); |
1197 |
1239 |
1198 // Any valid marker may come after QCC marker |
1240 // Any valid marker may come after QCC marker |
1199 iFHState = EStateInUnknown; |
1241 iFHState = EStateInUnknown; |
1200 |
1242 |
1201 return EFrameComplete; |
1243 return EFrameComplete; |
1265 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
1307 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
1266 |
1308 |
1267 // Append RGN to the current tile and decrement the tile length |
1309 // Append RGN to the current tile and decrement the tile length |
1268 tile.AppendRGNL( rgnMarker, markerLength + KMarkerSize ); |
1310 tile.AppendRGNL( rgnMarker, markerLength + KMarkerSize ); |
1269 } |
1311 } |
1270 CleanupStack::Pop(); |
1312 CleanupStack::PopAndDestroy(rgnMarker); |
1271 |
1313 |
1272 // Any valid marker may come after RGN marker |
1314 // Any valid marker may come after RGN marker |
1273 iFHState = EStateInUnknown; |
1315 iFHState = EStateInUnknown; |
1274 |
1316 |
1275 return EFrameComplete; |
1317 return EFrameComplete; |
1405 // Underflow, will keep reading |
1447 // Underflow, will keep reading |
1406 isUnderflow = ETrue; |
1448 isUnderflow = ETrue; |
1407 } |
1449 } |
1408 |
1450 |
1409 TPPMMarker *ppmMarker = new ( ELeave ) TPPMMarker; |
1451 TPPMMarker *ppmMarker = new ( ELeave ) TPPMMarker; |
1410 CleanupDeletePushL( ppmMarker ); |
1452 CleanupStack::PushL( ppmMarker ); |
1411 |
1453 |
1412 ppmMarker->iZppm = *iReader.iPtr++; |
1454 ppmMarker->iZppm = *iReader.iPtr++; |
1413 TUint32 entries = (TUint32)( markerLength - KMarkerSize - 1 ); |
1455 TUint32 entries = (TUint32)( markerLength - KMarkerSize - 1 ); |
1414 |
1456 |
1415 ppmMarker->iNppm = entries; |
1457 ppmMarker->iNppm = entries; |
1416 ppmMarker->iIppm = HBufC8::NewL( entries ); |
1458 ppmMarker->iIppm = HBufC8::NewL( entries ); |
|
1459 CleanupStack::PushL( ppmMarker->iIppm ); |
1417 |
1460 |
1418 if ( !isUnderflow ) |
1461 if ( !isUnderflow ) |
1419 { |
1462 { |
1420 ppmMarker->iIppm->Des( ).Append( iReader.iPtr, entries ); |
1463 ppmMarker->iIppm->Des( ).Append( iReader.iPtr, entries ); |
1421 iReader.iPtr += entries; |
1464 iReader.iPtr += entries; |
1620 iReader.iPtr -= KMarkerMinLength; |
1664 iReader.iPtr -= KMarkerMinLength; |
1621 return EFrameIncomplete; |
1665 return EFrameIncomplete; |
1622 } |
1666 } |
1623 |
1667 |
1624 TPLMMarker *plmMarker = new ( ELeave ) TPLMMarker; |
1668 TPLMMarker *plmMarker = new ( ELeave ) TPLMMarker; |
1625 CleanupDeletePushL( plmMarker ); |
1669 CleanupStack::PushL( plmMarker ); |
1626 |
1670 |
1627 plmMarker->iZplm = *iReader.iPtr++; |
1671 plmMarker->iZplm = *iReader.iPtr++; |
1628 TUint32 entries = (TUint32)( markerLength - KMarkerSize - 1 ); |
1672 TUint32 entries = (TUint32)( markerLength - KMarkerSize - 1 ); |
1629 |
1673 |
1630 plmMarker->iNplm = (TUint8)entries; |
1674 plmMarker->iNplm = (TUint8)entries; |
1631 plmMarker->iIplm = HBufC8::NewL( entries ); |
1675 plmMarker->iIplm = HBufC8::NewL( entries ); |
|
1676 CleanupStack::PushL( plmMarker->iIplm ); |
1632 plmMarker->iIplm->Des().Append( iReader.iPtr, entries ); |
1677 plmMarker->iIplm->Des().Append( iReader.iPtr, entries ); |
1633 iReader.iPtr += entries; |
1678 iReader.iPtr += entries; |
1634 |
1679 |
1635 // Make sure we read all the data |
1680 // Make sure we read all the data |
1636 if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) ) |
1681 if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) ) |
1765 { |
1811 { |
1766 // Underflow, will keep reading |
1812 // Underflow, will keep reading |
1767 isUnderflow = ETrue; |
1813 isUnderflow = ETrue; |
1768 } |
1814 } |
1769 |
1815 |
1770 TCOMMarker* comMarker = new ( ELeave ) TCOMMarker; |
1816 TCOMMarker* comMarker = new ( ELeave ) TCOMMarker; |
1771 CleanupDeletePushL( comMarker ); |
1817 //CleanupDeletePushL(comMarker); |
|
1818 CleanupStack::PushL( comMarker ); |
1772 |
1819 |
1773 comMarker->iRcom = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ); |
1820 comMarker->iRcom = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ); |
1774 TInt entries = markerLength - ( 2 * KMarkerSize ); |
1821 TInt entries = markerLength - ( 2 * KMarkerSize ); |
1775 |
1822 |
1776 comMarker->iCcom = HBufC8::NewL( entries ); |
1823 comMarker->iCcom = HBufC8::NewL( entries ); |
|
1824 //CleanupDeletePushL( comMarker->iCcom ); |
|
1825 CleanupStack::PushL(comMarker->iCcom); |
1777 if ( !isUnderflow ) |
1826 if ( !isUnderflow ) |
1778 { |
1827 { |
1779 comMarker->iCcom->Des().Append( iReader.iPtr, entries ); |
1828 comMarker->iCcom->Des().Append( iReader.iPtr, entries ); |
1780 iReader.iPtr += entries; |
1829 iReader.iPtr += entries; |
1781 iPreviousCOM = 0; |
1830 iPreviousCOM = 0; |
1877 sotMarker.iIsot = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ); |
1927 sotMarker.iIsot = PtrReadUtil::ReadBigEndianUint16Inc( iReader.iPtr ); |
1878 sotMarker.iPsot = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr ); |
1928 sotMarker.iPsot = PtrReadUtil::ReadBigEndianUint32Inc( iReader.iPtr ); |
1879 sotMarker.iTPsot = *iReader.iPtr++; |
1929 sotMarker.iTPsot = *iReader.iPtr++; |
1880 sotMarker.iTNsot = *iReader.iPtr++; |
1930 sotMarker.iTNsot = *iReader.iPtr++; |
1881 |
1931 |
1882 if(sotMarker.iIsot >= ( iImageInfo->NumOfHorizTiles() * iImageInfo->NumOfVertTiles() )) |
1932 if(sotMarker.iIsot >= ( iImageInfo->NumOfHorizTilesL() * iImageInfo->NumOfVertTilesL() )) |
1883 { |
1933 { |
1884 // Invalid tile index, exceeds the number of tiles, exit |
1934 // Invalid tile index, exceeds the number of tiles, exit |
1885 User::Leave( KErrCorrupt ); |
1935 User::Leave( KErrCorrupt ); |
1886 } |
1936 } |
1887 |
1937 |
2300 iReader.iPtr -= KMarkerMinLength; |
2350 iReader.iPtr -= KMarkerMinLength; |
2301 return EFrameIncomplete; |
2351 return EFrameIncomplete; |
2302 } |
2352 } |
2303 |
2353 |
2304 TPPTMarker *pptMarker = new ( ELeave ) TPPTMarker; |
2354 TPPTMarker *pptMarker = new ( ELeave ) TPPTMarker; |
2305 CleanupDeletePushL( pptMarker ); |
2355 CleanupStack::PushL( pptMarker ); |
2306 |
2356 |
2307 TInt entries = markerLength - KMarkerSize - 1; |
2357 TInt entries = markerLength - KMarkerSize - 1; |
2308 pptMarker->iZppt = *iReader.iPtr++; |
2358 pptMarker->iZppt = *iReader.iPtr++; |
2309 pptMarker->iIppt = HBufC8::NewL( entries ); |
2359 pptMarker->iIppt = HBufC8::NewL( entries ); |
|
2360 CleanupStack::PushL( pptMarker->iIppt ); |
2310 pptMarker->iIppt->Des( ).Append( iReader.iPtr, entries ); |
2361 pptMarker->iIppt->Des( ).Append( iReader.iPtr, entries ); |
2311 iReader.iPtr += entries; |
2362 iReader.iPtr += entries; |
2312 |
2363 |
2313 // Make sure we read all the data |
2364 // Make sure we read all the data |
2314 if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) ) |
2365 if ( ( iReader.iPtr - iReader.iPtrStartMarker ) != ( markerLength + KMarkerSize ) ) |
2319 |
2370 |
2320 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
2371 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
2321 |
2372 |
2322 // Append PPT to the current tile and decrement the tile length |
2373 // Append PPT to the current tile and decrement the tile length |
2323 tile.AppendPPTL( pptMarker, markerLength + KMarkerSize ); |
2374 tile.AppendPPTL( pptMarker, markerLength + KMarkerSize ); |
2324 CleanupStack::Pop(); |
2375 CleanupStack::Pop(pptMarker->iIppt); |
|
2376 CleanupStack::PopAndDestroy(pptMarker); |
2325 |
2377 |
2326 // Any valid marker may come after PPT marker |
2378 // Any valid marker may come after PPT marker |
2327 iFHState = EStateInUnknown; |
2379 iFHState = EStateInUnknown; |
2328 |
2380 |
2329 return EFrameComplete; |
2381 return EFrameComplete; |
2380 |
2432 |
2381 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
2433 CJ2kTileInfo& tile = CONST_CAST( CJ2kTileInfo&, iImageInfo->TileAt( iLastTileIndex ) ); |
2382 |
2434 |
2383 // Append PLT to the current tile and decrement the tile length |
2435 // Append PLT to the current tile and decrement the tile length |
2384 tile.AppendPLTL( pltMarker, markerLength + KMarkerSize ); |
2436 tile.AppendPLTL( pltMarker, markerLength + KMarkerSize ); |
2385 CleanupStack::Pop(); |
2437 //CleanupStack::Pop(); |
|
2438 CleanupStack::PopAndDestroy(pltMarker); |
2386 |
2439 |
2387 // Any valid marker may come after PLT marker |
2440 // Any valid marker may come after PLT marker |
2388 iFHState = EStateInUnknown; |
2441 iFHState = EStateInUnknown; |
2389 |
2442 |
2390 return EFrameComplete; |
2443 return EFrameComplete; |