VM Maker: VMMaker.oscog-eem.2461.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscog-eem.2461.mcz

commits-2
 
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2461.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.2461
Author: eem
Time: 18 October 2018, 5:18:40.11449 pm
UUID: b3cd33f5-6309-43a1-b669-7a1805111f34
Ancestors: VMMaker.oscog-eem.2460

Plugins:
BitBltSimulation
Fix a bug where the copyBits primitive read past the end of the source bitmap.  sourceSkewAndPointerInit would sometimes compute preload true and skew truye before then setting skew to -32.  There was a hack fix in copyLoop, but the real bug in copyLoop was the inner loop special case for rule 3 (over, or STORE).  It must fall back to the loop beginning "thisWord := self srcLongAt: sourceIndex." when preload is false, only using the loop beginning "self dstLongAt: destIndex put: prevWord." when preload and: [hDr = 1] is true.  Simplify the preload calculation in sourceSkewAndPointerInit by computing a mask similar to mask1 and comparing it against mask1 to see that no bits would be lost (if the mask computed for source is larger than mask1 then a preload is necessary).  Hence simplify the unskew and skewMask setup in copyLoop.

Improve the performance of primitiveDisplayString by pulling the lockSurfaces and unlockSurfaces implicit in copyBits out of the loop and replacing copytBits with copyBitsLockedAndClipped in the loop.

Fix primitivePixelValueAt so that it simulates correctly.

Other plugins:
Remove null implementations of initialiseModule and/or shutdownModule.  The loader/unloader nvokes these only if they exiust, consequently null versions are simply a waste of time and space.

Simulation:
Add support for computing the hash of the destination bitmap after copyBits in BitBltSimulator which was key in identifying the cases for which the above BitBltSimulation>>copyLoop bug fix applied.

Rewrite JPEGReadWriter2Plugin so that it simulates.  This is now a nice example of a recursive SmartSyntaxPlugin; the simulation of the plugin relies on the real implementation of the plugin in the underlying VM.

Fix InterpreterProxy>>byteSizeOf: for 64-bits and for bits objects.  Implement CArray>>asByteArray & CArray>>overwriteContentsWith: to ease copying bytes to/from the heap when simulating primitives (key for the JPEGReadWriter2Plugin simulation support).

Fix the return value of InterpreterProxy halt during simulation.

=============== Diff against VMMaker.oscog-eem.2460 ===============

Item was changed:
  ----- Method: BitBltSimulation>>copyLoop (in category 'inner loop') -----
  copyLoop
  | prevWord thisWord skewWord halftoneWord mergeWord hInc y unskew skewMask notSkewMask mergeFnwith destWord |
  "This version of the inner loop assumes noSource = false."
  <inline: false>
  <var: #prevWord type: #'unsigned int'>
  <var: #thisWord type: #'unsigned int'>
  <var: #skewWord type: #'unsigned int'>
  <var: #halftoneWord type: #'unsigned int'>
  <var: #mergeWord type: #'unsigned int'>
  <var: #destWord type: #'unsigned int'>
  <var: #skewMask type: #'unsigned int'>
  <var: #notSkewMask type: #'unsigned int'>
  <var: #unskew type: #int> "unskew is a bitShift and MUST remain signed, while skewMask is unsigned."
  <var: #mergeFnwith declareC: 'unsigned int (*mergeFnwith)(unsigned int, unsigned int)'>
  mergeFnwith := self cCoerce: (opTable at: combinationRule+1) to: 'unsigned int (*)(unsigned int, unsigned int)'.
  mergeFnwith.  "null ref for compiler"
 
+ self deny: (preload and: [skew = 0]).
+ self assert: (skew between: -31 and: 31).
+
  hInc := hDir * 4.  "Byte delta"
+ skew < 0
+ ifTrue: [unskew := skew + 32. skewMask := AllOnes << (0 - skew).
+ self cCode: [] inSmalltalk: [skewMask := skewMask bitAnd: 16rFFFFFFFF]]
- "degenerate skew fixed for Sparc. 10/20/96 ikp"
- skew = -32
- ifTrue: [skew := unskew := skewMask := 0]
  ifFalse:
+ [skew = 0
+ ifTrue: [unskew := 0. skewMask := AllOnes]
+ ifFalse: [unskew := skew - 32. skewMask := AllOnes >> skew]].
+
- [skew < 0
- ifTrue:
- [unskew := skew+32.
- skewMask := AllOnes << (0-skew)]
- ifFalse:
- [skew = 0
- ifTrue:
- [unskew := 0.
- skewMask := AllOnes]
- ifFalse:
- [unskew := skew-32.
- skewMask := AllOnes >> skew]]].
  notSkewMask := skewMask bitInvert32.
  noHalftone
  ifTrue: [halftoneWord := AllOnes.  halftoneHeight := 0]
  ifFalse: [halftoneWord := self halftoneAt: 0].
 
  y := dy.
  "Here is the vertical loop, in two versions, one for the combinationRule = 3 copy mode, one for the general case."
  combinationRule = 3
  ifTrue:
  [1 to: bbH do: "here is the vertical loop for combinationRule = 3 copy mode; no need to call merge"
  [ :i |
  halftoneHeight > 1 ifTrue:  "Otherwise, its always the same"
  [halftoneWord := self halftoneAt: y.
  y := y + vDir].
  preload
  ifTrue: "load the 64-bit shifter"
  [prevWord := self srcLongAt: sourceIndex.
  self incSrcIndex: hInc]
  ifFalse:
  [prevWord := 0].
 
  "Note: the horizontal loop has been expanded into three parts for speed:"
 
  "This first section requires masking of the destination store..."
  destMask := mask1.
  thisWord := self srcLongAt: sourceIndex.  "pick up next word"
  self incSrcIndex: hInc.
  skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew)
  bitOr:  "32-bit rotate"
  ((thisWord bitAnd: skewMask) bitShift: skew).
  prevWord := thisWord.
  destWord := self dstLongAt: destIndex.
  destWord := (destMask bitAnd: (skewWord bitAnd: halftoneWord))
  bitOr: (destWord bitAnd: destMask bitInvert32).
  self dstLongAt: destIndex put: destWord.
  self incDestIndex: hInc.
 
  "This central horizontal loop requires no store masking"
  destMask := AllOnes.
  (skew = 0 and: [halftoneWord = AllOnes])
  ifTrue: "Very special inner loop for STORE mode with no skew -- just move words"
+ [(preload and: [hDir = 1])
+ ifTrue:
- [hDir = -1
- ifTrue: "Woeful patch: revert to older code for hDir = -1"
  [2 to: nWords-1 do:
- [ :word |
- thisWord := self srcLongAt: sourceIndex.
- self incSrcIndex: hInc.
- self dstLongAt: destIndex put: thisWord.
- self incDestIndex: hInc]]
- ifFalse:
- [2 to: nWords-1 do:
  [ :word |  "Note loop starts with prevWord loaded (due to preload)"
  self dstLongAt: destIndex put: prevWord.
  self incDestIndex: hInc.
  prevWord := self srcLongAt: sourceIndex.
+ self incSrcIndex: hInc]]
+ ifFalse:
+ [2 to: nWords-1 do:
+ [ :word |
+ thisWord := self srcLongAt: sourceIndex.
+ self incSrcIndex: hInc.
+ self dstLongAt: destIndex put: thisWord.
+ self incDestIndex: hInc].
+ prevWord := thisWord]]
- self incSrcIndex: hInc]]]
  ifFalse:
  [2 to: nWords-1 do:
  [ :word |
  thisWord := self srcLongAt: sourceIndex.
  self incSrcIndex: hInc.
  skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew)
  bitOr:  "32-bit rotate"
  ((thisWord bitAnd: skewMask) bitShift: skew).
  prevWord := thisWord.
  self dstLongAt: destIndex put: (skewWord bitAnd: halftoneWord).
  self incDestIndex: hInc]].
 
  "This last section, if used, requires masking of the destination store..."
  nWords > 1 ifTrue:
  [destMask := mask2.
  thisWord := self srcLongAt: sourceIndex.  "pick up next word"
  self incSrcIndex: hInc.
  skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew)
  bitOr:  "32-bit rotate"
  ((thisWord bitAnd: skewMask) bitShift: skew).
  destWord := self dstLongAt: destIndex.
  destWord := (destMask bitAnd: (skewWord bitAnd: halftoneWord))
  bitOr: (destWord bitAnd: destMask bitInvert32).
  self dstLongAt: destIndex put: destWord.
  self incDestIndex: hInc].
 
  self incSrcIndex: sourceDelta.
  self incDestIndex: destDelta]]
  ifFalse:
  [1 to: bbH do: "here is the vertical loop for the general case (combinationRule ~= 3)"
  [ :i |
  halftoneHeight > 1 ifTrue:  "Otherwise, its always the same"
  [halftoneWord := self halftoneAt: y.
  y := y + vDir].
  preload
  ifTrue: "load the 64-bit shifter"
  [prevWord := self srcLongAt: sourceIndex.
  self incSrcIndex: hInc]
  ifFalse:
  [prevWord := 0].
 
  "Note: the horizontal loop has been expanded into three parts for speed:"
 
  "This first section requires masking of the destination store..."
  destMask := mask1.
  thisWord := self srcLongAt: sourceIndex.  "pick up next word"
  self incSrcIndex: hInc.
  skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew)
  bitOr:  "32-bit rotate"
  ((thisWord bitAnd: skewMask) bitShift: skew).
  prevWord := thisWord.
  destWord := self dstLongAt: destIndex.
  mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: destWord.
  destWord := (destMask bitAnd: mergeWord)
  bitOr: (destWord bitAnd: destMask bitInvert32).
  self dstLongAt: destIndex put: destWord.
  self incDestIndex: hInc.
 
  "This central horizontal loop requires no store masking"
  destMask := AllOnes.
  2 to: nWords-1 do: "Normal inner loop does merge:"
  [ :word |
  thisWord := self srcLongAt: sourceIndex.  "pick up next word"
  self incSrcIndex: hInc.
  skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew)
  bitOr:  "32-bit rotate"
  ((thisWord bitAnd: skewMask) bitShift: skew).
  prevWord := thisWord.
  mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord)
  with: (self dstLongAt: destIndex).
  self dstLongAt: destIndex put: mergeWord.
  self incDestIndex: hInc].
 
  "This last section, if used, requires masking of the destination store..."
  nWords > 1 ifTrue:
  [destMask := mask2.
  thisWord := self srcLongAt: sourceIndex.  "pick up next word"
  self incSrcIndex: hInc.
  skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew)
  bitOr:  "32-bit rotate"
  ((thisWord bitAnd: skewMask) bitShift: skew).
  destWord := self dstLongAt: destIndex.
  mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: destWord.
  destWord := (destMask bitAnd: mergeWord)
  bitOr: (destWord bitAnd: destMask bitInvert32).
  self dstLongAt: destIndex put: destWord.
  self incDestIndex: hInc].
 
  self incSrcIndex: sourceDelta.
  self incDestIndex: destDelta]]!

Item was changed:
  ----- Method: BitBltSimulation>>destMaskAndPointerInit (in category 'setup') -----
  destMaskAndPointerInit
  "Compute masks for left and right destination words"
  | startBits pixPerM1 endBits |
  <inline: true>
  pixPerM1 := destPPW - 1.  "A mask, assuming power of two"
  "how many pixels in first word"
  startBits := destPPW - (dx bitAnd: pixPerM1).
- destMSB
- ifTrue:[ mask1 := AllOnes >> (32 - (startBits*destDepth))]
- ifFalse:[ mask1 := AllOnes << (32 - (startBits*destDepth))].
  "how many pixels in last word"
+ endBits := (dx + bbW - 1 bitAnd: pixPerM1) + 1.
+ destMSB
+ ifTrue:
+ [mask1 := AllOnes >> (32 - (startBits * destDepth)).
+ mask2 := AllOnes << (32 - (endBits * destDepth))]
+ ifFalse:
+ [mask1 := AllOnes << (32 - (startBits * destDepth)).
+ mask2 := AllOnes >> (32 - (endBits * destDepth))].
+ self cCode: [] inSmalltalk:
+ [mask1 := mask1 bitAnd: 16rFFFFFFFF.
+ mask2 := mask2 bitAnd: 16rFFFFFFFF].
+
- endBits := ((dx + bbW - 1) bitAnd: pixPerM1) + 1.
- destMSB
- ifTrue:[mask2 := AllOnes << (32 - (endBits*destDepth))]
- ifFalse:[mask2 := AllOnes >> (32 - (endBits*destDepth))].
  "determine number of words stored per line; merge masks if only 1"
  bbW < startBits
  ifTrue: [mask1 := mask1 bitAnd: mask2.
  mask2 := 0.
  nWords := 1]
+ ifFalse: [nWords := bbW - startBits + pixPerM1 // destPPW + 1].
- ifFalse: [nWords := (bbW - startBits) + pixPerM1 // destPPW + 1].
  hDir := vDir := 1. "defaults for no overlap with source"
 
  "calculate byte addr and delta, based on first word of data"
  "Note pitch is bytes and nWords is longs, not bytes"
+ destIndex := destBits + (dy * destPitch) + ((dx // destPPW) * 4).
+ destDelta := destPitch * vDir - (4 * (nWords * hDir)) "byte addr delta"!
- destIndex := destBits + (dy * destPitch) + ((dx // destPPW) *4).
- destDelta := destPitch * vDir - (4 * (nWords * hDir)).  "byte addr delta"
- !

Item was changed:
  ----- Method: BitBltSimulation>>primitiveDisplayString (in category 'primitives') -----
  primitiveDisplayString
-
- | kernDelta xTable glyphMap stopIndex startIndex sourceString bbObj maxGlyph ascii glyphIndex sourcePtr left quickBlt |
  <export: true>
+ | kernDelta xTable glyphMap stopIndex startIndex sourceString bbObj maxGlyph ascii glyphIndex sourcePtr left quickBlt |
+ <var: #sourcePtr type: #'char *'>
- <var: #sourcePtr type: 'char *'>
  interpreterProxy methodArgumentCount = 6 ifFalse:
  [^interpreterProxy primitiveFail].
  kernDelta := interpreterProxy stackIntegerValue: 0.
  xTable := interpreterProxy stackValue: 1.
  glyphMap := interpreterProxy stackValue: 2.
  stopIndex := interpreterProxy stackIntegerValue: 3.
  startIndex := interpreterProxy stackIntegerValue: 4.
  sourceString := interpreterProxy stackValue: 5.
  bbObj := interpreterProxy stackObjectValue: 6.
  interpreterProxy failed ifTrue:
  [^nil].
 
  ((interpreterProxy isArray: xTable)
  and: [(interpreterProxy isArray: glyphMap)
  and: [(interpreterProxy slotSizeOf: glyphMap) = 256
  and: [(interpreterProxy isBytes: sourceString)
  and: [startIndex > 0
  and: [stopIndex >= 0 "to avoid failing for empty strings..."
  and: [stopIndex <= (interpreterProxy byteSizeOf: sourceString)
  and: [(self loadBitBltFrom: bbObj)
  and: [combinationRule ~= 30 "these two need extra source alpha"
  and: [combinationRule ~= 31]]]]]]]]]) ifFalse:
  [^interpreterProxy primitiveFail].
  stopIndex = 0 ifTrue:
  [^interpreterProxy pop: 6 "the string is empty; pop args, return rcvr"].
  maxGlyph := (interpreterProxy slotSizeOf: xTable) - 2.
  "See if we can go directly into copyLoopPixMap (usually we can)"
  quickBlt := destBits ~= 0 "no OS surfaces please"
  and:[sourceBits ~= 0 "and again"
  and:[noSource = false "needs a source"
  and:[sourceForm ~= destForm "no blits onto self"
  and:[cmFlags ~= 0
  or:[sourceMSB ~= destMSB
  or:[sourceDepth ~= destDepth]]]]]]. "no point using slower version"
+ quickBlt
+ ifTrue:
+ [endOfSource := sourceBits + (sourcePitch * sourceHeight).
+ endOfDestination := destBits + (destPitch * destHeight)]
+ ifFalse:
+ [self lockSurfaces ifFalse:
+ [^interpreterProxy primitiveFail]].
- quickBlt ifTrue:
- [endOfSource := sourceBits + (sourcePitch * sourceHeight).
- endOfDestination := destBits + (destPitch * destHeight)].
  left := destX.
  sourcePtr := interpreterProxy firstIndexableField: sourceString.
  startIndex to: stopIndex do:
  [:charIndex|
  ascii := interpreterProxy byteAtPointer: sourcePtr + charIndex - 1.
  glyphIndex := interpreterProxy fetchInteger: ascii ofObject: glyphMap.
+ (glyphIndex < 0 or: [glyphIndex > maxGlyph])  ifTrue:
- (glyphIndex < 0 or:[glyphIndex > maxGlyph])  ifTrue:
  [^interpreterProxy primitiveFail].
  sourceX := interpreterProxy fetchInteger: glyphIndex ofObject: xTable.
+ width := (interpreterProxy fetchInteger: glyphIndex + 1 ofObject: xTable) - sourceX.
+ interpreterProxy failed ifTrue:
+ [^nil].
- width := (interpreterProxy fetchInteger: glyphIndex+1 ofObject: xTable) - sourceX.
- interpreterProxy failed ifTrue:[^nil].
  self clipRange. "Must clip here"
  (bbW > 0 and: [bbH > 0]) ifTrue:
  [quickBlt
  ifTrue:
  [self destMaskAndPointerInit.
  self copyLoopPixMap.
  "both, hDir and vDir are known to be > 0"
  affectedL := dx.
  affectedR := dx + bbW.
  affectedT := dy.
  affectedB := dy + bbH]
  ifFalse:
+ [self copyBitsLockedAndClipped]].
+ interpreterProxy failed ifTrue:
+ [^nil].
+ destX := destX + width + kernDelta].
- [self copyBits]]. "but this means we're doing lockSurfaces/unlockSurfaces *for each character* :-( eem 10/16/2018 15:42"
- interpreterProxy failed ifTrue:[^nil].
- destX := destX + width + kernDelta.
- ].
  affectedL := left.
+ quickBlt ifFalse:
+ [self unlockSurfaces].
  self showDisplayBits.
  "store destX back"
  interpreterProxy storeInteger: BBDestXIndex ofObject: bbObj withValue: destX.
  interpreterProxy pop: 6 "pop args, return rcvr"!

Item was changed:
  ----- Method: BitBltSimulation>>sourceSkewAndPointerInit (in category 'setup') -----
  sourceSkewAndPointerInit
  "This is only used when source and dest are same depth,
  ie, when the barrel-shift copy loop is used."
+ | sxLowBits dxLowBits pixPerM1 startBits m1 |
- | dWid sxLowBits dxLowBits pixPerM1 |
  <inline: true>
+ <var: 'm1' type: #'unsigned int'>
+ self assert: (destPPW = sourcePPW and: [destMSB = sourceMSB and: [destDepth = sourceDepth]]).
  pixPerM1 := destPPW - 1.  "A mask, assuming power of two"
  sxLowBits := sx bitAnd: pixPerM1.
  dxLowBits := dx bitAnd: pixPerM1.
+ "how many pixels in first word"
+ startBits := hDir > 0
+ ifTrue: [sourcePPW - (sx bitAnd: pixPerM1)]
+ ifFalse: [(sx + bbW - 1 bitAnd: pixPerM1) + 1].
+ m1 := destMSB
+ ifTrue: [AllOnes >> (32 - (startBits * destDepth))]
+ ifFalse: [AllOnes << (32 - (startBits * destDepth))].
+ preload := (m1 bitAnd: mask1) ~= mask1. "i.e. there are some missing bits"
- "check if need to preload buffer
- (i.e., two words of source needed for first word of destination)"
- hDir > 0 ifTrue:
- ["n Bits stored in 1st word of dest"
- dWid := bbW min: destPPW - dxLowBits.
- preload := (sxLowBits + dWid) > pixPerM1]
- ifFalse:
- [dWid := bbW min: dxLowBits + 1.
- preload := (sxLowBits - dWid + 1) < 0].
 
  "calculate right-shift skew from source to dest"
  skew := destDepth * (sourceMSB ifTrue: [sxLowBits - dxLowBits] ifFalse: [dxLowBits - sxLowBits]).  " -32..32 "
  preload ifTrue:
  [skew := skew < 0 ifTrue: [skew + 32] ifFalse: [skew - 32]].
 
  "Calc byte addr and delta from longWord info"
  sourceIndex := sourceBits + (sy * sourcePitch) + ((sx // (32 // sourceDepth)) * 4).
  "calculate increments from end of 1 line to start of next"
  sourceDelta := (sourcePitch * vDir) - (4 * (nWords * hDir)).
 
  preload ifTrue: "Compensate for extra source word fetched"
+ [sourceDelta := sourceDelta - (4 * hDir)].
+
+ self deny: (preload and: [skew = 0]).
+ self assert: (skew between: -31 and: 31)!
- [sourceDelta := sourceDelta - (4 * hDir)]!

Item was changed:
  ----- Method: BitBltSimulation>>unlockSurfaces (in category 'surface support') -----
  unlockSurfaces
  "Unlock the bits of any OS surfaces."
  "See the comment in lockSurfaces. Similar rules apply. That is, the area provided in ioUnlockSurface
  can be used to determine the dirty region after drawing. If a source is unlocked, then the area will
  be (0,0,0,0) to indicate that no portion is dirty.  Note that if a GC happens during unlockSourceFn
  (if it is effectively a callback) no matter.  No bits are touched after unlock."
  | sourceHandle destHandle destLocked |
  hasSurfaceLock ifFalse: [^self].
  unlockSurfaceFn = 0 ifTrue:
  [self loadSurfacePlugin ifFalse:
  [^self]].
  self ensureDestAndSourceFormsAreValid.
  destLocked := false.
  destHandle := interpreterProxy fetchPointer: FormBitsIndex ofObject: destForm.
  (interpreterProxy isIntegerObject: destHandle) ifTrue: "The destBits are always assumed to be dirty"
  [self unlockSurfaceFn: (interpreterProxy integerValueOf: destHandle)
  _: affectedL
  _: affectedT
  _: affectedR - affectedL
  _: affectedB - affectedT.
  destBits := destPitch := 0.
  destLocked := true].
  noSource ifFalse:
  [self ensureDestAndSourceFormsAreValid.
  sourceHandle := interpreterProxy fetchPointer: FormBitsIndex ofObject: sourceForm.
  (interpreterProxy isIntegerObject: sourceHandle) ifTrue:
  ["Only unlock sourceHandle if different from destHandle"
  (destLocked and: [sourceHandle = destHandle]) ifFalse:
+ [self unlockSurfaceFn: (interpreterProxy integerValueOf: sourceHandle) _: 0 _: 0 _: 0 _: 0].
- [self unlock: (interpreterProxy integerValueOf: sourceHandle) Sur: 0 fa: 0 ce: 0 Fn: 0].
  sourceBits := sourcePitch := 0]].
+ hasSurfaceLock := false!
- hasSurfaceLock := false.
- self cCode: [] inSmalltalk:
- [interpreterProxy displayObject = destForm ifTrue:
- [interpreterProxy getDeferDisplayUpdates ifFalse:
- [interpreterProxy fullDisplayUpdate]]]!

Item was changed:
  BitBltSimulation subclass: #BitBltSimulator
+ instanceVariableNames: 'destinationHashes copyBitsCount copyBitsBreakCount'
- instanceVariableNames: ''
  classVariableNames: ''
  poolDictionaries: ''
  category: 'VMMaker-InterpreterSimulation'!
  BitBltSimulator class
  instanceVariableNames: 'opTable maskTable warpBitShiftTable ditherMatrix4x4 ditherThresholds16 ditherValues16 dither8Lookup isInitialised'!
 
+ !BitBltSimulator commentStamp: 'eem 10/18/2018 17:17' prior: 0!
+ Provide bitblt support for the vm simulator.
+
+ Instance Variables
+ copyBitsBreakCount: <Integer|nil>
+ copyBitsCount: <Integer|nil>
+ destinationHashes: <OrderedCollection|nil>
+
+ copyBitsBreakCount
+ - if set, and destinationHashes is non-nil, copyBits will halt at this count
+
+ copyBitsCount
+ - if destinationHashes is non-nil this counts copyBits invocations
+
+ destinationHashes
+ - if an empty OrderedCollection then this will collect the hash of the destination bitmap after each copyBits operation.
+  if a non-empty OrderedCollection, then the hash of the destination bitmap will be compared to the corresponding hash
+  in destinationHashes after each copyBits operation, halting if there is a mismatch.
+  if nil, then nothing is done.  In this way one can track down regressions by collecting hashes in the unregressed version
+  and comparing against results in the regressed version.!
- !BitBltSimulator commentStamp: 'tpr 5/5/2003 12:22' prior: 0!
- Provide bitblt support for the vm simulator!
  BitBltSimulator class
  instanceVariableNames: 'opTable maskTable warpBitShiftTable ditherMatrix4x4 ditherThresholds16 ditherValues16 dither8Lookup isInitialised'!

Item was added:
+ ----- Method: BitBltSimulator>>copyBits (in category 'debug support') -----
+ copyBits
+ (destinationHashes notNil and: [copyBitsCount + 1 = copyBitsBreakCount]) ifTrue:
+ [self halt: 'reached copyBitsBreakCount ', copyBitsBreakCount printString].
+ super copyBits.
+ (interpreterProxy failed
+ or: [destinationHashes isNil]) ifFalse:
+ [copyBitsCount ifNil: [copyBitsCount := 0].
+ (copyBitsCount := copyBitsCount + 1) <= destinationHashes size
+ ifTrue:
+ [(destinationHashes at: copyBitsCount) ~= self destinationHash ifTrue:
+ [self halt: 'destination different']]
+ ifFalse:
+ [destinationHashes addLast: self destinationHash]]!

Item was added:
+ ----- Method: BitBltSimulator>>copyBitsBreakCount (in category 'debug support') -----
+ copyBitsBreakCount
+
+ ^ copyBitsBreakCount!

Item was added:
+ ----- Method: BitBltSimulator>>copyBitsBreakCount: (in category 'debug support') -----
+ copyBitsBreakCount: anObject
+
+ copyBitsBreakCount := anObject!

Item was added:
+ ----- Method: BitBltSimulator>>copyBitsCount (in category 'debug support') -----
+ copyBitsCount
+
+ ^ copyBitsCount!

Item was added:
+ ----- Method: BitBltSimulator>>copyBitsCount: (in category 'debug support') -----
+ copyBitsCount: anObject
+
+ copyBitsCount := anObject!

Item was changed:
  ----- Method: BitBltSimulator>>cppIf:ifTrue:ifFalse: (in category 'translation support') -----
  cppIf: conditionBlockOrSymbolValue ifTrue: trueExpressionOrBlock ifFalse: falseExpressionOrBlockOrNil
  "The simulator does not have fast blt defines"
+ ^ conditionBlockOrSymbolValue == #'ENABLE_FAST_BLT'
- ^ conditionBlockOrSymbolValue = #'ENABLE_FAST_BLT'
  ifTrue: falseExpressionOrBlockOrNil
  ifFalse: [super
  cppIf: conditionBlockOrSymbolValue
  ifTrue: trueExpressionOrBlock
  ifFalse: falseExpressionOrBlockOrNil]!

Item was added:
+ ----- Method: BitBltSimulator>>destinationHash (in category 'debug support') -----
+ destinationHash
+ | mem bits |
+ mem := interpreterProxy memory.
+ bits := mem copyFrom: destBits // mem bytesPerElement + 1 to: endOfDestination // mem bytesPerElement.
+ ByteArray adoptInstance: bits.
+ "This must be (and is) true; but the copyFrom:to: short cut is 100x faster than the byteAt: version"
+ "self assert: (((destBits to: endOfDestination - 1) collect: [:i| interpreterProxy byteAt: i]) as: ByteArray) = bits"
+ ^bits hash!

Item was added:
+ ----- Method: BitBltSimulator>>destinationHashes (in category 'debug support') -----
+ destinationHashes
+
+ ^ destinationHashes!

Item was added:
+ ----- Method: BitBltSimulator>>destinationHashes: (in category 'debug support') -----
+ destinationHashes: anObject
+
+ destinationHashes := anObject.
+ copyBitsCount ifNil: [copyBitsCount := 0].
+ copyBitsBreakCount ifNil: [copyBitsBreakCount := -1]!

Item was changed:
+ ----- Method: BitBltSimulator>>primitivePixelValueAt (in category 'primitives') -----
- ----- Method: BitBltSimulator>>primitivePixelValueAt (in category 'simulation') -----
  primitivePixelValueAt
+ "This is a hack to mimic the SmartSyntaxPlugin support for primitive:parameters:receiver:
+ which is hacked here at BitBltSimulator>>primitive:parameters:receiver:"
+ | xVal yVal |
+ xVal := interpreterProxy stackIntegerValue: 1.
+ yVal := interpreterProxy stackIntegerValue: 0.
+ interpreterProxy failed ifFalse:
+ [self primitivePixelValueAtX: xVal y: yVal]!
- self primitivePixelValueAtX: (interpreterProxy stackValue: 1) y: (interpreterProxy stackValue: 0)!

Item was added:
+ ----- Method: CArray>>asByteArray (in category 'converting') -----
+ asByteArray
+ "Answer a ByteArray containing the receivers contents"
+ | size bytes base |
+ size := interpreter byteSizeOf: self cPtrAsOop.
+ bytes := ByteArray new: size.
+ base := arrayBaseAddress + ptrOffset - 1.
+ 1 to: size do:
+ [:index|
+ bytes at: index put: (interpreter byteAt: base + index)].
+ ^bytes!

Item was added:
+ ----- Method: CArray>>overwriteContentsWith: (in category 'accessing') -----
+ overwriteContentsWith: aByteArray
+ | base size |
+ self assert: (interpreter isWordsOrBytes: self cPtrAsOop).
+ size := (interpreter byteSizeOf: self cPtrAsOop) min: aByteArray size.
+ base := arrayBaseAddress + ptrOffset - 1.
+ 1 to: size do:
+ [:index|
+ interpreter byteAt: base + index put: (aByteArray at: index)]!

Item was removed:
- ----- Method: ImmX11Plugin>>initialiseModule (in category 'initialize-release') -----
- initialiseModule
-
- <export: true>
- ^ true
- !

Item was removed:
- ----- Method: ImmX11Plugin>>shutdownModule (in category 'initialize-release') -----
- shutdownModule
-
- <export: true>
- ^ true
- !

Item was changed:
  ----- Method: InterpreterPlugin>>halt (in category 'debugging') -----
  halt
+ self cCode: '' inSmalltalk: [^super halt "avoid the ^0 below"].
- self cCode: '' inSmalltalk: [nil halt].
  ^0!

Item was changed:
  ----- Method: InterpreterProxy>>byteSizeOf: (in category 'object access') -----
  byteSizeOf: oop
  "Return the size of the receiver in bytes"
+ ^oop class isBits
+ ifTrue: [oop basicSize * oop class elementSize]
+ ifFalse: [(self slotSizeOf: oop) * Smalltalk wordSize]!
- ^oop class isBytes
- ifTrue:[(self slotSizeOf: oop)]
- ifFalse:[(self slotSizeOf: oop) * 4]!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin class>>simulatorClass (in category 'simulation') -----
+ simulatorClass
+ ^SmartSyntaxPluginSimulator!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>compressStructSize (in category 'plugin support') -----
+ compressStructSize
+ <inline: #always>
+ ^self
+ cCode: [self sizeof: #'struct jpeg_compress_struct']
+ inSmalltalk: [JPEGReadWriter2 new primJPEGCompressStructSize]!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>decompressStructSize (in category 'plugin support') -----
+ decompressStructSize
+ <inline: #always>
+ ^self
+ cCode: [self sizeof: #'struct jpeg_decompress_struct']
+ inSmalltalk: [JPEGReadWriter2 new primJPEGDecompressStructSize]!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>errorMgr2StructSize (in category 'plugin support') -----
+ errorMgr2StructSize
+ <inline: #always>
+ ^self
+ cCode: [self sizeof: #'struct error_mgr2']
+ inSmalltalk: [JPEGReadWriter2 new primJPEGErrorMgr2StructSize]!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>evaluateIfFailed: (in category 'simulation') -----
+ evaluateIfFailed: aBlock
+ "Evaluate aBlock, catching primtiive failure, and failing if so.
+ Answer if evaluating aBlock caused primitive failure."
+ <doNotGenerate>
+ aBlock
+ on: Error
+ do: [:ex|
+ ((ex signalerContext selector beginsWith: #primitiveFailed) "e.g. could be error: sent from primitiveFailed:"
+ or: [ex signalerContext sender selector beginsWith: #primitiveFailed]) ifFalse:
+ [ex pass].
+ interpreterProxy primitiveFail.
+ ^true].
+ ^false!

Item was removed:
- ----- Method: JPEGReadWriter2Plugin>>initialiseModule (in category 'initialize-release') -----
- initialiseModule
-
- <export: true>
- ^true!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>isValidCompressionStruct: (in category 'plugin support') -----
+ isValidCompressionStruct: aByteArray
+ <inline: #always>
+ ^(interpreterProxy byteSizeOf: (self cCode: [aByteArray] inSmalltalk: [aByteArray cPtrAsOop])) >= self compressStructSize!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>isValidDecompressionStruct: (in category 'plugin support') -----
+ isValidDecompressionStruct: aByteArray
+ <inline: #always>
+ ^(interpreterProxy byteSizeOf: (self cCode: [aByteArray] inSmalltalk: [aByteArray cPtrAsOop])) >= self decompressStructSize!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>isValidErrorMessageStruct: (in category 'plugin support') -----
+ isValidErrorMessageStruct: aByteArray
+ <inline: #always>
+ ^(interpreterProxy byteSizeOf: (self cCode: [aByteArray] inSmalltalk: [aByteArray cPtrAsOop])) >= self errorMgr2StructSize!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primImageHeight: (in category 'primitives') -----
  primImageHeight: aJPEGDecompressStruct
-
  <export: true>
+ self primitive: 'primImageHeight' parameters: #(ByteArray).
 
- self
- primitive: 'primImageHeight'
- parameters: #(ByteArray).
-
  "Various parameter checks"
+ (self isValidDecompressionStruct: aJPEGDecompressStruct) ifFalse:
+ [^interpreterProxy primitiveFail].
- self cCode: '
- interpreterProxy->success
- ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(0))) >= (sizeof(struct jpeg_decompress_struct)));
- if (interpreterProxy->failed()) return null;
- ' inSmalltalk: [].
 
+ ^(self
+ cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->image_height'
+ inSmalltalk: [JPEGReadWriter2 new primImageHeight: aJPEGDecompressStruct asByteArray])
+ asOop: SmallInteger!
- ^(self cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->image_height' inSmalltalk: [0])
- asOop: SmallInteger!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primImageNumComponents: (in category 'primitives') -----
  primImageNumComponents: aJPEGDecompressStruct
-
  <export: true>
+ self primitive: 'primImageNumComponents' parameters: #(ByteArray).
 
- self
- primitive: 'primImageNumComponents'
- parameters: #(ByteArray).
-
  "Various parameter checks"
+ (self isValidDecompressionStruct: aJPEGDecompressStruct) ifFalse:
+ [^interpreterProxy primitiveFail].
- self cCode: '
- interpreterProxy->success
- ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(0))) >= (sizeof(struct jpeg_decompress_struct)));
- if (interpreterProxy->failed()) return null;
- ' inSmalltalk: [].
 
+ ^(self
+ cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->num_components'
+ inSmalltalk: [JPEGReadWriter2 new primImageNumComponents: aJPEGDecompressStruct asByteArray])
+ asOop: SmallInteger!
- ^(self cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->num_components' inSmalltalk: [0])
- asOop: SmallInteger!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primImageWidth: (in category 'primitives') -----
  primImageWidth: aJPEGDecompressStruct
-
  <export: true>
+ self primitive: 'primImageWidth' parameters: #(ByteArray).
 
- self
- primitive: 'primImageWidth'
- parameters: #(ByteArray).
-
  "Various parameter checks"
+ (self isValidDecompressionStruct: aJPEGDecompressStruct) ifFalse:
+ [^interpreterProxy primitiveFail].
- self cCode: '
- interpreterProxy->success
- ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(0))) >= (sizeof(struct jpeg_decompress_struct)));
- if (interpreterProxy->failed()) return null;
- ' inSmalltalk: [].
 
+ ^(self
+ cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->image_width'
+ inSmalltalk: [JPEGReadWriter2 new primImageWidth: aJPEGDecompressStruct asByteArray])
+ asOop: SmallInteger!
- ^(self cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->image_width' inSmalltalk: [0])
- asOop: SmallInteger!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primJPEGCompressStructSize (in category 'primitives') -----
  primJPEGCompressStructSize
  <export: true>
+ self primitive: #primJPEGCompressStructSize parameters: #().
 
+ ^self compressStructSize asOop: SmallInteger!
- self
- primitive: 'primJPEGCompressStructSize'
- parameters: #().
-
- ^(self cCode: 'sizeof(struct jpeg_compress_struct)' inSmalltalk: [0])
- asOop: SmallInteger!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primJPEGDecompressStructSize (in category 'primitives') -----
  primJPEGDecompressStructSize
  <export: true>
+ self primitive: #primJPEGDecompressStructSize parameters: #().
 
+ ^self decompressStructSize asOop: SmallInteger!
- self
- primitive: 'primJPEGDecompressStructSize'
- parameters: #().
-
- ^(self cCode: 'sizeof(struct jpeg_decompress_struct)' inSmalltalk: [0])
- asOop: SmallInteger!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primJPEGErrorMgr2StructSize (in category 'primitives') -----
  primJPEGErrorMgr2StructSize
  <export: true>
+ self primitive: #primJPEGErrorMgr2StructSize parameters: #().
- self
- primitive: 'primJPEGErrorMgr2StructSize'
- parameters: #().
 
+ ^self errorMgr2StructSize asOop: SmallInteger!
- ^(self cCode: 'sizeof(struct error_mgr2)' inSmalltalk: [0])
- asOop: SmallInteger!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primJPEGPluginIsPresent (in category 'primitives') -----
  primJPEGPluginIsPresent
  <export: true>
+ self primitive: #primJPEGPluginIsPresent parameters: #().
+
+ ^(self cCode: [true] inSmalltalk: [JPEGReadWriter2 primJPEGPluginIsPresent]) asOop: Boolean!
- self
- primitive: 'primJPEGPluginIsPresent'
- parameters: #().
- ^true asOop: Boolean!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primJPEGReadHeader:fromByteArray:errorMgr: (in category 'primitives') -----
  primJPEGReadHeader: aJPEGDecompressStruct fromByteArray: source errorMgr: aJPEGErrorMgr2Struct
-
- | sourceSize |
-
  <export: true>
 
+ | sourceSize |
  self
  primitive: 'primJPEGReadHeaderfromByteArrayerrorMgr'
  parameters: #(ByteArray ByteArray ByteArray).
 
  "Various parameter checks"
+ ((self isValidDecompressionStruct: aJPEGDecompressStruct)
+ and: [self isValidErrorMessageStruct: aJPEGErrorMgr2Struct]) ifFalse:
+ [^interpreterProxy primitiveFail].
- interpreterProxy success:
- (self cCode: 'interpreterProxy->stSizeOf(interpreterProxy->stackValue(2)) >= (sizeof(struct jpeg_decompress_struct))' inSmalltalk: []).
- interpreterProxy success:
- (self cCode: 'interpreterProxy->stSizeOf(interpreterProxy->stackValue(0)) >= (sizeof(struct error_mgr2))' inSmalltalk: []).
- interpreterProxy failed ifTrue: [ ^ nil ].
 
+ sourceSize := interpreterProxy byteSizeOf: source.
- sourceSize := interpreterProxy stSizeOf: (interpreterProxy stackValue: 1).
  sourceSize > 0 ifTrue:
  [self primJPEGReadHeader: aJPEGDecompressStruct
  fromByteArray: source
  size: sourceSize
  errorMgrReadHeader: aJPEGErrorMgr2Struct]!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>primJPEGReadHeader:fromByteArray:size:errorMgrReadHeader: (in category 'simulation') -----
+ primJPEGReadHeader: jpegDecompressStruct fromByteArray: source size: sourceSize errorMgrReadHeader: jpegErrorMgr2Struct
+ "void primJPEGReadHeaderfromByteArraysizeerrorMgrReadHeader(
+ char* jpegDecompressStruct,
+ char* source,
+ unsigned int sourceSize,
+ char* jpegErrorMgr2Struct)"
+ <doNotGenerate>
+ | decompressStruct errorStruct sourceBytes |
+ sourceBytes := source asByteArray.
+ self assert: sourceBytes size >= sourceSize.
+ decompressStruct := jpegDecompressStruct asByteArray.
+ errorStruct := jpegErrorMgr2Struct asByteArray.
+ (self evaluateIfFailed:
+ [JPEGReadWriter2 new
+ primJPEGReadHeader: decompressStruct
+ fromByteArray: sourceBytes
+ errorMgr: errorStruct]) ifTrue: [^nil].
+ jpegDecompressStruct overwriteContentsWith: decompressStruct.
+ jpegErrorMgr2Struct overwriteContentsWith: errorStruct.
+ source overwriteContentsWith: sourceBytes.
+ ^nil!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primJPEGReadImage:fromByteArray:onForm:doDithering:errorMgr: (in category 'primitives') -----
  primJPEGReadImage: aJPEGDecompressStruct fromByteArray: source onForm: form doDithering: ditherFlag errorMgr: aJPEGErrorMgr2Struct
-
- | formBitmap formNativeDepth formDepth formWidth formHeight pixelsPerWord formPitch formBitmapSizeInBytes sourceSize formBitmapOOP formComponentBitSize formComponents wordsPerRow |
  <export: true>
+ | formBitmap formNativeDepth formDepth formWidth formHeight pixelsPerWord formPitch formBitmapSizeInBytes sourceSize formBitmapOOP formComponentBitSize formComponents wordsPerRow |
+ <var: #formBitmap type: #'unsigned int *'>
- <var: #formBitmap type: 'unsigned int*'>
 
  self
  primitive: 'primJPEGReadImagefromByteArrayonFormdoDitheringerrorMgr'
  parameters: #(ByteArray ByteArray Form Boolean ByteArray).
 
  formBitmapOOP := interpreterProxy fetchPointer: 0 ofObject: form.
  formNativeDepth := interpreterProxy fetchInteger: 3 ofObject: form.
  formWidth := interpreterProxy fetchInteger: 1 ofObject: form.
  formHeight := interpreterProxy fetchInteger: 2 ofObject: form.
  formDepth := formNativeDepth abs.
 
  "Various parameter checks"
+ ((self isValidDecompressionStruct: aJPEGDecompressStruct)
+ and: [self isValidErrorMessageStruct: aJPEGErrorMgr2Struct]) ifFalse:
+ [^interpreterProxy primitiveFail].
- interpreterProxy success:
- (self cCode: 'interpreterProxy->stSizeOf(interpreterProxy->stackValue(4)) >= (sizeof(struct jpeg_decompress_struct))' inSmalltalk: []).
- interpreterProxy success:
- (self cCode: 'interpreterProxy->stSizeOf(interpreterProxy->stackValue(0)) >= (sizeof(struct error_mgr2))' inSmalltalk: []).
- interpreterProxy failed ifTrue: [ ^ nil ].
 
  formComponents := formDepth ~= 8 ifTrue: [4] ifFalse: [1].
  formComponentBitSize := formDepth ~= 16 ifTrue: [8] ifFalse: [4].
  pixelsPerWord := 32 // (formComponents * formComponentBitSize).
  wordsPerRow := (formWidth + pixelsPerWord - 1) // pixelsPerWord.
  formPitch := formWidth + (pixelsPerWord-1) // pixelsPerWord * 4.
  formBitmapSizeInBytes := interpreterProxy byteSizeOf: formBitmapOOP.
 
  interpreterProxy success:
+ ((interpreterProxy isWordsOrBytes: formBitmapOOP)
+ and: [formBitmapSizeInBytes >= (formPitch * formHeight)]).
+ interpreterProxy failed ifTrue: [^nil].
- ((interpreterProxy isWordsOrBytes: formBitmapOOP) and:
- [formBitmapSizeInBytes >= (formPitch * formHeight)]).
- interpreterProxy failed ifTrue: [^ nil].
 
  sourceSize := interpreterProxy stSizeOf: (interpreterProxy stackValue: 3).
 
  interpreterProxy success: (sourceSize ~= 0).
+ interpreterProxy failed ifTrue: [^nil].
- interpreterProxy failed ifTrue: [  ^ nil ].
 
  formBitmap := interpreterProxy firstIndexableField: formBitmapOOP.
 
+ self primJPEGReadImagefromByteArrayonFormdoDitheringerrorMgrReadScanlines: aJPEGDecompressStruct
+     _: aJPEGErrorMgr2Struct
+ _: source
+     _: sourceSize
+     _: ditherFlag
+     _: formBitmap
+   _: pixelsPerWord
+   _: wordsPerRow
+     _: formNativeDepth!
- self
- cCode: 'primJPEGReadImagefromByteArrayonFormdoDitheringerrorMgrReadScanlines(
- aJPEGDecompressStruct,
-     aJPEGErrorMgr2Struct,
- source,
-     sourceSize,
-     ditherFlag,
-     formBitmap,
-     pixelsPerWord,
-     wordsPerRow,
-     formNativeDepth);'
- inSmalltalk: [].!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>primJPEGReadImagefromByteArrayonFormdoDitheringerrorMgrReadScanlines:_:_:_:_:_:_:_:_: (in category 'simulation') -----
+ primJPEGReadImagefromByteArrayonFormdoDitheringerrorMgrReadScanlines: jpegDecompressStruct _: jpegErrorMgr2Struct _: source _: sourceSize _: ditherFlag _: formBitmap _: pixelsPerWord _: wordsPerRow _: formNativeDepth
+ "void primJPEGReadImagefromByteArrayonFormdoDitheringerrorMgrReadScanlines(
+    char* jpegDecompressStruct,
+    char* jpegErrorMgr2Struct,
+    char* source,
+    unsigned int sourceSize,
+    int ditherFlag,
+    unsigned int* bitmap,
+    unsigned int pixelsPerWord,
+    unsigned int wordsPerRow,
+    int nativeDepth)"
+ <doNotGenerate>
+ | sourceBytes decompressStruct errorStruct form |
+ sourceBytes := source asByteArray.
+ decompressStruct := jpegDecompressStruct asByteArray.
+ errorStruct := jpegErrorMgr2Struct asByteArray.
+ (self evaluateIfFailed:
+ [| slave height |
+ slave := JPEGReadWriter2 new.
+ height := slave primImageWidth: decompressStruct. "cheating ;-)"
+ form := Form extent: wordsPerRow * pixelsPerWord @ height depth: formNativeDepth.
+ slave
+ primJPEGReadImage: decompressStruct
+ fromByteArray: sourceBytes
+ onForm: form
+ doDithering: true
+ errorMgr: errorStruct]) ifTrue: [^nil].
+ jpegDecompressStruct overwriteContentsWith: decompressStruct.
+ jpegErrorMgr2Struct overwriteContentsWith: errorStruct.
+ source overwriteContentsWith: sourceBytes. "could happen..."
+ ByteArray adoptInstance: form bits.
+ formBitmap overwriteContentsWith: form bits.
+ ^nil!

Item was changed:
  ----- Method: JPEGReadWriter2Plugin>>primJPEGWriteImage:onByteArray:form:quality:progressiveJPEG:errorMgr: (in category 'primitives') -----
  primJPEGWriteImage: aJPEGCompressStruct onByteArray: destination form: form quality: quality progressiveJPEG: progressiveFlag errorMgr: aJPEGErrorMgr2Struct
 
  | formBitmap formWidth formHeight formNativeDepth formDepth destinationSize pixelsPerWord wordsPerRow formPitch formBitmapSizeInBytes formBitmapOOP formComponentBitSize formComponents |
  <export: true>
  <var: #formBitmap type: 'unsigned int *'>
  <var: #destinationSize type: 'unsigned int'>
 
  self
  primitive: 'primJPEGWriteImageonByteArrayformqualityprogressiveJPEGerrorMgr'
  parameters: #(ByteArray ByteArray Form SmallInteger Boolean ByteArray).
 
  formBitmapOOP := interpreterProxy fetchPointer: 0 ofObject: form.
  formWidth := interpreterProxy fetchInteger: 1 ofObject: form.
  formHeight := interpreterProxy fetchInteger: 2 ofObject: form.
  formNativeDepth := interpreterProxy fetchInteger: 3 ofObject: form.
  formDepth := formNativeDepth abs.
 
  "Various parameter checks"
+ ((self isValidCompressionStruct: aJPEGCompressStruct)
+ and: [self isValidErrorMessageStruct: aJPEGErrorMgr2Struct]) ifFalse:
+ [^interpreterProxy primitiveFail].
+
- interpreterProxy success:
- (self cCode: 'interpreterProxy->stSizeOf(interpreterProxy->stackValue(5)) >= (sizeof(struct jpeg_compress_struct))' inSmalltalk: []).
- interpreterProxy success:
- (self cCode: 'interpreterProxy->stSizeOf(interpreterProxy->stackValue(0)) >= (sizeof(struct error_mgr2))' inSmalltalk: []).
- interpreterProxy failed ifTrue: [ ^ nil ].
 
  formComponents := formDepth ~= 8 ifTrue: [4] ifFalse: [1].
  formComponentBitSize := formDepth ~= 16 ifTrue: [8] ifFalse: [4].
  pixelsPerWord := 32 // (formComponents * formComponentBitSize).
  wordsPerRow := (formWidth + pixelsPerWord - 1) // pixelsPerWord.
  formPitch := wordsPerRow * 4.
  formBitmapSizeInBytes := interpreterProxy byteSizeOf: formBitmapOOP.
  interpreterProxy success:
  ((interpreterProxy isWordsOrBytes: formBitmapOOP) and:
  [formBitmapSizeInBytes >= (formPitch * formHeight)]).
  interpreterProxy failed ifTrue: [ ^ nil ].
 
  formBitmap := interpreterProxy firstIndexableField: formBitmapOOP.
  destinationSize := interpreterProxy stSizeOf: (interpreterProxy stackValue: 4).
+ destinationSize > 0 ifTrue:
+ [self primJPEGWriteImageonByteArrayformqualityprogressiveJPEGerrorMgrWriteScanlines: formWidth
+ _: formHeight
+ _: formNativeDepth
+ _: formBitmap
+ _: aJPEGCompressStruct
+ _: aJPEGErrorMgr2Struct
+ _: quality
+ _: progressiveFlag
+ _: pixelsPerWord
+ _: wordsPerRow
+ _: destination
+ _: (self addressOf: destinationSize put: [:v| destinationSize := v])].
- (destinationSize = 0)
- ifFalse: [ self
- cCode: ' primJPEGWriteImageonByteArrayformqualityprogressiveJPEGerrorMgrWriteScanlines(
- formWidth,
- formHeight,
- formNativeDepth,
- formBitmap,
- aJPEGCompressStruct,
- aJPEGErrorMgr2Struct,
- quality,
- progressiveFlag,
- pixelsPerWord,
- wordsPerRow,
- destination,
- &destinationSize);'
- inSmalltalk: []].
 
+ ^destinationSize asOop: SmallInteger!
- ^(self cCode: 'destinationSize' inSmalltalk: [0])
- asOop: SmallInteger!

Item was added:
+ ----- Method: JPEGReadWriter2Plugin>>primJPEGWriteImageonByteArrayformqualityprogressiveJPEGerrorMgrWriteScanlines:_:_:_:_:_:_:_:_:_:_:_: (in category 'simulation') -----
+ primJPEGWriteImageonByteArrayformqualityprogressiveJPEGerrorMgrWriteScanlines: width _: height _: nativeDepth _: bitmap _: jpegCompressStruct _: jpegErrorMgr2Struct _: quality _: progressiveFlag _: pixelsPerWord _: wordsPerRow _: destination _: destinationSizePtr
+ "void primJPEGWriteImageonByteArrayformqualityprogressiveJPEGerrorMgrWriteScanlines(
+ unsigned int width,
+ unsigned int height,
+ int nativeDepth,
+ unsigned int* bitmap,
+ char* jpegCompressStruct,
+ char* jpegErrorMgr2Struct,
+ int quality,
+ int progressiveFlag,
+ unsigned int pixelsPerWord,
+ unsigned int wordsPerRow,
+ char* destination,
+ unsigned int* destinationSizePtr)"
+ <doNotGenerate>
+ | bits form compressStruct errorStruct destinationBytes destinationSize |
+ bits := bitmap asByteArray.
+ Bitmap adoptInstance: bits.
+ form := Form extent: width @ height depth: nativeDepth bits: bits.
+ compressStruct := jpegCompressStruct asByteArray.
+ errorStruct := jpegErrorMgr2Struct asByteArray.
+ destinationBytes := destination asByteArray.
+ (self evaluateIfFailed:
+ [destinationSize :=JPEGReadWriter2 new
+ primJPEGWriteImage: compressStruct
+ onByteArray: destinationBytes
+ form: form
+ quality: quality
+ progressiveJPEG: progressiveFlag
+ errorMgr: errorStruct]) ifTrue: [^nil].
+ jpegCompressStruct overwriteContentsWith: compressStruct.
+ jpegErrorMgr2Struct overwriteContentsWith: errorStruct.
+ destination overwriteContentsWith: destinationBytes.
+ destinationSizePtr at: 0 put: destinationSize.
+ ^nil!

Item was removed:
- ----- Method: JPEGReadWriter2Plugin>>shutdownModule (in category 'initialize-release') -----
- shutdownModule
-
- <export: true>
- ^true!

Item was changed:
  ----- Method: Mpeg3Plugin>>initialiseModule (in category 'support') -----
  initialiseModule
  <export: true>
  maximumNumberOfFilesToWatch := 1024.
  1 to: maximumNumberOfFilesToWatch do: [:i | mpegFiles at: i put: 0].
+ ^true!
- ^self cCode: 'true' inSmalltalk:[true]!

Item was changed:
  ----- Method: Mpeg3Plugin>>shutdownModule (in category 'support') -----
  shutdownModule
  <export: true>
  1 to: maximumNumberOfFilesToWatch do:
  [:i | ((mpegFiles at: i) ~= 0) ifTrue:
  [self cCode: 'mpeg3_close(mpegFiles[i])'.
  mpegFiles at: i put: 0]].
+ ^true!
- ^self cCode:  'true' inSmalltalk:[true]!